ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Python-2133-타일 채우기
    Problem Solving 2020. 12. 15. 19:24

    타일 채우기

    이번주 내내 고민했던 문제였다.
    블로그 풀이들을 봐도 이해가 잘 안됐었는데, 오늘 결국 이해를 해서 다른 블로그들 보다 조금 더 자세하게 설명해보려 한다.

    그림을 통해 이해를 시도하기 전에 짚고 넘어가야할 부분이 몇가지 있다.

    1. 먼저, N X 3 크기의 벽에서 N이 홀수인 경우에는 2 X 1 타일 혹은 1 X 2 타일로 벽을 완전히 채울 수 없다. 타일의 넓이는 2로 짝수임으로 벽의 넓이도 짝수인 경우에만 벽을 완전히 채울 수 있다.

    2. 다음으로, 2 X 3크기의 벽을 채우는 경우의 수는 3가지이다. (그려보자)

    3. 마지막으로, N X 3(N%2==0) 크기의 벽에 타일을 배열할 때
      1) 세로로 나눌 수 없게_ 배치하는 경우의 수는
      2) N에 상관 없이 2가지이다.


     

    • 1)세로로 나눌 수 없는 경우란?

    Crepe

    왼쪽의 경우 벽을 세로로 나눌 수 없게 배치한 경우이다.
    오른쪽의 경우는 벽을 세로로 더 작게 나눌 수 있게 배치한 경우이다.

    • 2)N에 상관 없이 2가지?

    Crepe

    4와 6일 때, 위와 같이 더 작게 나눌 수 없는 경우의 수는 각각 2가지씩 이다. 4, 6, 8, 10, ... 모두 2개씩 존재한다.


    4 X 3 크기의 벽 까지는 손으로 그려서 확인해 볼 수도 있음으로 6부터 설명을 할 예정이다.
    가로의 길이가 4인 벽을 채우는 경우의 수는 11이다.



    6 X 3 크기의 벽을 채우는 경우의 수

    Crepe

    위의 그림에서 가로길이가 N인 '빨간색' 박스는 가로 길이가 N보다 작은 박스들로 더이상 나눌 수 없는 박스를 의미한다.

    세로 기준으로 나뉠 수 있는 경우들을 살펴보면 아래와 같이 4가지 경우가 나뉜다.

    • 2 X 3 크기의 벽 + 2 X 3 크기의 벽 + 2 X 3 크기의 벽으로 나눌 수 있는 경우
    • 4 X 3 크기의 벽 + 2 X 3 크기의 벽으로 나눌 수 있는 경우
    • 2 X 3 크기의 벽 + 4 X 3 크기의 벽으로 나눌 수 있는 경우
    • 세로로 나눌 수 없는 6 X 3 크기의 벽인 경우

    이 네가지 경우를 왼쪽 '빨간색' 박스 기준으로 조금 줄여보면 다시 세가지 경우로 나뉠 수 있다.

    • 빨간색 박스의 가로 길이가 2인 경우 >> 2)에 의해서 가로길이가 2인 박스를 채우는 경우의 수는 3이다.
    • 빨간색 박스의 가로 길이가 4인 경우 >> 3)에 의해서 가로길이가 4인 박스를 채우는 경우의 수는 2이다.
    • 빨간색 박스의 가로 길이가 6인 경우 >> 3)에 의해서 가로길이가 6인 박스를 채우는 경우의 수는 2이다.

    따라서 가로 길이가 6인 벽을 채우는 경우의 수는

    • 가로 길이가 4인 흰색 박스를 채우는 경우의 수 X 가로 길이가 2인 빨간색 박스를 채우는 경우의 수
    • 가로 길이가 2인 흰색 박스를 채우는 경우의 수 X 가로 길이가 4인 빨간색 박스를 채우는 경우의 수
    • 가로 길이가 6인 빨간색 박스를 채우는 경우의 수

    를 모두 합한 값이다.

    11×3 + 3×2 + 2 = 𝟒𝟏


     

    8 X 3 크기의 벽을 채우는 경우의 수

    Crepe

    • 빨간색 박스의 가로 길이가 2, 4, 6, 8 인 경우로 나눌 수 있다.

    따라서 가로 길이가 8인 벽을 채우는 경우의 수는

    • 가로 길이가 6인 흰색 박스를 채우는 경우의 수 X 가로 길이가 2인 빨간색 박스를 채우는 경우의 수
    • 가로 길이가 4인 흰색 박스를 채우는 경우의 수 X 가로 길이가 4인 빨간색 박스를 채우는 경우의 수
    • 가로 길이가 2인 흰색 박스를 채우는 경우의 수 X 가로 길이가 6인 빨간색 박스를 채우는 경우의 수
    • 가로 길이가 8인 빨간색 박스를 채우는 경우의 수

    를 모두 합한 값이다.

    41×3 + (11+3)×2 + 2 = 𝟏𝟓𝟑

     


    이를 토대로 dp 점화식을 세우면 아래와 같음을 알 수 있다!

    • n이 홀수인 경우는 모두 0임으로 홀수 경우를 모두 제외하고 N에 2를 나눈 값을 i에 대입했다.
    𝑑𝑝[𝑖] = 𝑑𝑝[𝑖−1]×3 + 𝑠𝑢𝑚(𝑑𝑝[:𝑖−1])×2 + 2
    • 위의 방법이 헷갈린다면, N을 2로 나누지 않고, 아래와 같은 점화식을 사용해도 무방하다.
    if i%2==0:
        𝑑𝑝[𝑖] = 𝑑𝑝[𝑖−2]×3 + 𝑠𝑢𝑚(𝑑𝑝[:𝑖−2])×2 + 2
    else:
        dp[i] = 0
    • 함께 공부하는 분이 알려주신 더 간단한 점화식도 살펴보자.
    𝑑𝑝[𝑖]
    
    = 𝑑𝑝[𝑖−1]×3 + 𝑠𝑢𝑚(𝑑𝑝[:𝑖−1])×2 + 2
    
    =  𝑑𝑝[𝑖−1]×3 + dp[i-2]x2 + 𝑠𝑢𝑚(𝑑𝑝[:𝑖−2])×2 + 2
    
    =  𝑑𝑝[𝑖−1]×3 + dp[i-2]x3 + 𝑠𝑢𝑚(𝑑𝑝[:𝑖−2])×2 + 2 - dp[i-2]
    
    =  𝑑𝑝[𝑖−1]×3 + dp[i-1] - dp[i-2]
       (dp[i-1] = dp[i-2]x3 + 𝑠𝑢𝑚(𝑑𝑝[:𝑖−2])×2 + 2)
    
    =  𝑑𝑝[𝑖−1]×4 - dp[i-2]

     

    구현

    위의 점화식에서 sum을 통해 dp[0] 부터 dp[i-2]까지 더하는 부분을 매번 해줘도 되지만, 시간복잡도를 줄이기 위해서 dp[i]에 sum(dp[:i+1])값도 저장하며 진행했다.

    #벽을 채우는 경우의 수 저장
    𝑑𝑝[𝑖] = 𝑑𝑝[𝑖−1]×3 + 𝑠𝑢𝑚(𝑑𝑝[:𝑖−1])×2 + 2
    #sum(dp[:i+1])값 저장
    dp[i][1] = dp[i][0] + dp[i-1][1]

     

    CODE

    import sys
    read = sys.stdin.readline
    
    n = int(read())
    # n이 홀수일 경우 벽을 채울 수 있는 방법이 없다.
    if n % 2 == 1:
        print(0)
        sys.exit()
    # 첫 번째 값에는 벽을 채울 수 있는 경우의 수,
    # 두 번째 값에는 dp 첫 번째 값들의 총 합을 저장한다.
    dp = list([0, 0] for _ in range(n//2+1))
    dp[1] = [3, 3]
    
    for i in range(2, n//2+1):
        dp[i][0] = dp[i-1][0]*3+dp[i-2][1]*2+2
        dp[i][1] = dp[i][0]+dp[i-1][1]
    
    print(dp[-1][0])

     

    틀린 부분이 있을 수 있습니다. 피드백 주시면 고치도록 하겠습니다!
    감사합니다.👍

    [꼭 다시 풀어보기]



    'Problem Solving' 카테고리의 다른 글

    Python-CodeForce#690(Div.3)_C-Unique Number  (0) 2020.12.16
    Python-14852-타일 채우기3  (1) 2020.12.15
    C++-1181-단어 정렬  (0) 2020.12.15
    Python-2751-수 정렬하기2  (0) 2020.12.14
    Python-9663-N-Queen  (0) 2020.12.13
Designed by Tistory.