[백준 BOJ_2447] 별 찍기 - 10 Python 풀이

출처: 백준 온라인 저지

문제

BOJ_2447_1 BOJ_2447_2

풀이 1

분할 정복 알고리즘을 이용하여 풀어보겠습니다.

분할 정복: 문제를 나눌 수 없을 때까지 나누어서 각각을 풀고 다시 합병하는 방법

N=27이라면 27*27을 9*9로, 9*9를 3*3로, 3*3을 1*1까지 분할시킬 수 있습니다.

아래는 3*3의 사각형의 빈 곳의 좌표(y, x)를 표시한 N=9의 윗부분 출력입니다.

*********
* ** ** * (1, 1) (1, 4) (1, 7)
*********

3*3 사각형의 경우는 y나 x의 값이 1, 4, 7 … 3m + 1일 때에만 빈 칸을 출력합니다.
다른 말로는 y나 x를 3으로 나누었을 때 나머지가 1일 경우에만 빈 칸을 출력합니다.

  • y % 3 = 1, x % 3 = 1

아래는 9*9의 사각형의 빈 곳의 좌표를 표시했습니다.

*********
* ** ** *
********* 
***   ***  (3, 3) (3, 4) (3, 5)
* *   * *  (4, 3) (4, 4) (4, 5)
***   ***  (5, 3) (5, 4) (5, 5)
*********
* ** ** *
*********

9*9 사각형은 y나 x를 3으로 한번 나눈 뒤의 값의 나머지가 1일 경우에 빈 칸을 출력합니다.

  • (y // 3) % 3 = 1, (x // 3) % 3 = 1

기저 사례는 y와 x를 3으로 나눌 때 나머지가 1일 때는 빈 칸(“ “)을, N이 1일 때는 가장 작은 사각형일 때이기 때문에 별(“*“)을 출력해줍니다.

그 뒤로는 y, x, n을 모두 3을 나눈 값으로 재귀호출을 해줍니다.

코드 1

def draw_star(y, x, n):
    if y % 3 == 1 and x % 3 == 1:
        print(" ", end="")
    elif n == 1:
        print("*", end="")
    else:
        draw_star(y // 3, x // 3, n // 3)
    
N = int(input())
for y in range(N):
    for x in range(N):
        draw_star(y, x, N)
    print()

풀이 1은 Output에는 문제없으나 아무래도 Python에서는 시간초과가 되었습니다.

풀이 2

Python으로 구현하고 싶은 욕심에 이것 저것 시도해 보았지만 도저히 어떻게 구현해야 될지 감이 안잡혀 구글링하는 도중 가장 이해가 되는 풀이를 찾을 수 있었습니다. 아래 링크의 3번째 풀이입니다.

풀이 출처 링크

예시를 들어 나름대로 해석해보겠습니다.

사각형을 윗 부분, 중간 부분, 밑 부분으로 나누어서 별을 찍어 주는 방법입니다.

  • 윗 부분은 (N//3)*(N//3)사각형을 3번 반복
  • 중간 부분은 (N//3)*(N//3)사각형을 1번, (N//3)*(N//3)만큼 비워주고 다시 (N//3)*(N//3)사각형을 1번
  • 밑 부분은 윗 부분과 동일

N=3일 때 block, top, mid의 값은

block = ["*"]
top = ["***"] # "*" * 3 = "***"
mid = ["* *"] # "*" + " " * (3//3) + "*" = "* *"

N=9일 때는

block = ["***", 
         "* *", 
         "***"]
top = ["*********", # "***" * 3 = "*********"
       "* ** ** *", # "* *" * 3 = "* ** ** *"
       "*********"] # "***" * 3 = "*********"
mid = ["***   ***", # "***" + " " * (9//3) + "***" = "***   ***"
       "* *   * *", # "* *" + " " * (9//3) + "* *" = "* *   * *"
       "***   ***"] # "***" + " " * (9//3) + "***" = "***   ***"

패턴이 보이기 시작합니다.

기저 사례는 더 이상 분할이 되지 않을 때인 N=1일 때 별(“*“)하나를 가진 리스트를 반환해줍니다.

그 뒤로는 N을 3으로 나눈 값으로 재귀 호출을 해줍니다.

마지막에는 윗 부분, 중간 부분, 밑 부분의 리스트를 합친 리스트를 반환해줍니다.

  • top + mid + top

코드 2

def draw(n):
    if n == 1:
        return ["*"]
    block = draw(n//3)
    top = [ b * 3 for b in block ]
    mid = [ b + " " * (n//3) + b for b in block ]
    return top + mid + top
    
N = int(input())
print("\n".join(draw(N)))

Leave a comment