문제

재귀적인 패턴으로 별을 찍어 보자. N이 3의 거듭제곱(3, 9, 27, ...)이라고 할 때, 크기 N의 패턴은 N×N 정사각형 모양이다.

크기 3의 패턴은 가운데에 공백이 있고, 가운데를 제외한 모든 칸에 별이 하나씩 있는 패턴이다.

***
* *
***

N이 3보다 클 경우, 크기 N의 패턴은 공백으로 채워진 가운데의 (N/3)×(N/3) 정사각형을 크기 N/3의 패턴으로 둘러싼 형태이다. 예를 들어 크기 27의 패턴은 예제 출력 1과 같다.

입력

첫째 줄에 N이 주어진다. N은 3의 거듭제곱이다. 즉 어떤 정수 k에 대해 N=3k이며, 이때 1 ≤ k < 8이다.

출력

첫째 줄부터 N번째 줄까지 별을 출력한다.

내가 푼 풀이

- 재귀호출로 위 패턴을 주어진 N만큼 호출하는건 알겠는데... 규칙을 찾기 어려웠다.

- 다른사람의 풀이를 참고했다. 해당 문제는 분할정복기법이다.

N = 3일때, 가운데를 제외하고 8군데를 그린다.

N = 9일때, N=3일때의 경우를 8군데 그린다.

N = 27일때, N=9일때의 경우를 8군데 그린다. -> N= 3일때의 경우를 64군데 그리면된다.

이를 재귀호출해주면 되는데 규칙은 가운데를 비우는것이다.

 

0,0 0,1 0,2
1,0 1,1 1,2
2,0 2,1 2,2

N=3일때 [1, 1] 을 제외한 8군데를 그린다.

이는 x % 3 = 1, y % 3 = 1 이 된다는것이다.

 

N=9일때 위 세칸을 보자

0,0 0,1 0,2 0,3 0,4 0,5 0,6 0,7 0,8
1,0 1,1 1,2 1,3 1,4 1,5 1,6 1,7 1,8
2,0 2,1 2,2 2,3 2,4 2,5 2,6 2,7 2,8

공백인 위치는 [1, 1], [1, 4], [1,7] 이 된다.

첫번째  [1, 1]: x % 3 = 1, y % 3 = 1

두번째 [1, 4]: x %3 = 1, y % 3 = 1

세번째 [1, 7]: x %3 = 1, y % 3 = 1 가 된다.

 

문제는 N = 9일때의 중간 공백이다.

중간공백의 좌표는 [3, 3], [3, 4] [3, 5] 등 9개가 있지만, 3 % 3 = 0이 된다.

그래서 위의 규칙과 같이 만들어 재귀호출을 하기 위해 왼쪽값을 3보다 작은값으로 만든다.

-> 3 / 3 % 3 = 1형식으로 만든다.

또한 N이 9를 넘어간다면  9 /3 = 3 이되고, 3%3은 0이 되므로 위의 규칙과 맞지않는다.

따라서 나눗셈의 오른쪽값은 왼쪽값보다 크거나 같아야 3보다 작은값으로 나뉘어 3으로 나눠도 0이되지않는다.

 

-> 재귀호출할때마다 N으로 나누어 0이나오면 N을 3으로 나누어 재귀호출한다.

 

이를 코드로 구현하면 다음과 같다.

import Foundation

// 입력받기
var N = Int(readLine()!)!
var out = ""

// 그리기함수
// a / b 일때 b가 a보다 크면 0이다.
// 그래서 b를 3으로 나누고 다시 재귀호출
func draw(x: Int, y: Int, num: Int) {
    if x / num % 3 == 1 && y / num % 3 == 1 {
        out += " "
    } else {
        if num / 3 == 0 {
            out += "*"
        } else {
            draw(x: x, y: y, num: num/3)
        }
    }
}

for i in 0..<N {
    for j in 0..<N {
        draw(x: i, y: j, num: N)
    }
    out += "\n"
}
print(out)

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-1024 수열의 합 Swift  (1) 2024.04.20
BOJ-1004 어린 왕자 Swift  (1) 2024.04.20
BOJ-2580 스도쿠 Swift  (0) 2024.04.15
BOJ-1013 Contact Swift  (0) 2024.04.15
BOJ-5430 AC Swift  (1) 2024.04.15

+ Recent posts