Notice
Recent Posts
Recent Comments
Link
«   2026/02   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
Archives
Today
Total
관리 메뉴

사고쳤어요

[백준] 2447 별 찍기 - 10 (C++) 본문

백준/Gold

[백준] 2447 별 찍기 - 10 (C++)

kevinmj12 2024. 10. 28. 18:32

링크: https://www.acmicpc.net/problem/2447

 

문제

재귀적인 패턴으로 별을 찍어 보자. 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번째 줄까지 별을 출력한다.

 


풀이

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

(1,1), (1,2), ... (3,3)까지 총 9개의 점이 있을 때 가운데만 공백으로 처리하고 나머지는 별로 채우면 된다.

이를 재귀로 간단히 작성하면 다음과 같이 풀이를 작성할 수 있다.

#include <iostream>
#include <vector>
using namespace std;

bool answer[6562][6562];

void solve(int n, int y, int x){
    if (n == 3){
        answer[y][x] = true;
        answer[y][x+1] = true;
        answer[y][x+2] = true;
        answer[y+1][x] = true;
        // 가운데 빈 칸
        answer[y+1][x+2] = true;
        answer[y+2][x] = true;
        answer[y+2][x+1] = true;
        answer[y+2][x+2] = true;
    }
    else{
        solve(n/3, y, x);
        solve(n/3, y, x + (n/3));
        solve(n/3, y, x + (2*n/3));
        solve(n/3, y + (n/3), x);
        // 가운데 빈 칸
        solve(n/3, y + (n/3), x + (2*n/3));
        solve(n/3, y + (2*n/3), x);
        solve(n/3, y + (2*n/3), x + (n/3));
        solve(n/3, y + (2*n/3), x + (2*n/3));
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);

    int n;
    cin >> n;

    solve(n, 0, 0);

    for (int i = 0; i < n; i++){
        for (int j = 0; j < n; j++){
            if (answer[i][j]){
                cout << "*";
            }
            else{
                cout << " ";
            }
        }
        cout << "\n";
    }
}

 

하지만 위 방법은 매우 많은 메모리를 차지한다. N은 최대 3^7 = 2187로 2187 * 2187 크기의 배열은 문제를 풀 때 충분히 여유롭지만 N의 거듭제곱이 더 커진다면 메모리가 충분하지 못할 것이다.

이를 해결하기 위해 배열에 값을 저장하지 않고 바로바로 계산하여 출력을 하도록 한 코드는 다음과 같다.

#include <iostream>
using namespace std;

void solve(int n, int y, int x){
    if ((y/n)%3 == 1 && (x/n)%3 == 1) {
        cout << " ";
    }
    else {
        if(n / 3 == 0)
            cout <<"*";
        else
            solve(n/3, y, x);
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);

    int n;
    cin >> n;

    for (int i = 0; i < n; i++){
        for (int j = 0; j < n; j++){
            solve(n, i, j);
        }
        cout << "\n";
    }
}

 

 

제출한 결과는 다음과 같은데 위가 배열에 값을 저장한 첫 번째 풀이, 아래가 두 번째 풀이이다.

확실히 각각 시간과 메모리에서 장점을 보이는 것을 확인할 수 있다.

'백준 > Gold' 카테고리의 다른 글

[백준] 1327 소트게임 (C++)  (0) 2024.11.11
[백준] 1826 연료 채우기 (C++)  (1) 2024.11.08
[백준] 2437 저울 (C++)  (4) 2024.10.08
[백준] 3079 입국심사 (C++)  (3) 2024.10.07
[백준] 11404 플로이드 (C++)  (0) 2024.08.29