[ 백준 ] 10997 / 별 찍기 - 22

18939 단어 psbojboj

# Appreciation

/*
 * Problem :: 10997 / 별 찍기 - 22
 *
 * Kind :: Math
 *
 * Insight
 * - 모양이 좀 이상한데...?
 *   N=1 에서 N=2 가 어떤 규칙에 따라서 연결이 되나...?
 *   N=2 에서 N=3 에서는 연결되는 규칙이 보이는데 N=1 에서 N=2 는 도저히 못찾겠다
 *   + N=1 을 그냥 특이케이스로 빼서 따로 생각하자
 *     # N=2 의 경우 이렇게 볼 수 있다
 *       *****     *****
 *       *         *   *  에서
 *       * ***     * *x*  위의 '에서' 바로 왼쪽에 있는 별표랑
 *       * * *  => * * *  x 친 곳을 바꾸어 주면 될 것 같은데?
 *       * * *     * * *
 *       *   *     *   *
 *       *****     *****
 *       -> 즉, 다음과 같이 생각하였다
 *
 *          N=1 일 때 그려지는 부분
 *          *    *
 *          * => *
 *          *    *
 *
 *          N=2 일 때 그려지는 부분
 *          *****    *****
 *          *   *    *
 *          *   *    *  **
 *          *   * => *   *
 *          *   *    *   *
 *          *   *    *   *
 *          *****    *****
 *
 *          N=3 일 때 그려지는 부분
 *          *********     *********
 *          *       *     *
 *          *       *     *      **
 *          *       *     *       *
 *          *       *     *       *
 *          *       *  => *       *
 *          *       *     *       *
 *          *       *     *       *
 *          *       *     *       *
 *          *       *     *       *
 *          *********     *********
 *
 * Point
 * - 재귀로 구현하는 게 좋을 것 같아 그렇게 구현했다
 *   for 문으로 별표를 찍어주어도 괜찮기 한데...
 *   막상 코딩해보니 너무 가독성이 떨어졌다
 *   + 직사각형 그리는 건데 그냥 점을 이동시켜서 찍는 것도 나쁘지 않을 것 같아서
 *     그렇게 구현했더니 나름 괜찮았다
 *     # 시작점을 정한다
 *       오른쪽으로 x 번 이동한다
 *       아래쪽으로 y 번 이동한다
 *       왼쪽으로 x 번 이동한다
 *       위쪽으로 y 번 위동한다
 *       다음에 그려야할 부분으로 넘어간다
 *     # 시작점을 구할 때 그림의 한 가운데의 좌표를 알고 있으면 편하기에
 *       이를 my, mx 라는 전역변수로 선언해서 사용하였다
 */

# Code

//
//  BOJ
//  ver.C++
//
//  Created by GGlifer
//
//  Open Source

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

#define endl '\n'

// Set up : Global Variables
int N;
char B[4*100-1][4*100-3];
int my, mx;
int dy[4] = {0, +1, 0, -1};
int dx[4] = {+1, 0, -1, 0};

// Set up : Functions Declaration
void f(int n);


int main()
{
    // Set up : I/O
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // Set up : Input
    cin >> N;

    // Control : Output
    if (N == 1) { /* N=1 은 특이케이스로 간주 */
        cout << "*" << endl;
        exit(0);
    }

    // Process
    memset(B, ' ', sizeof(B)); /* 빈칸으로 초기화 */
    my = 2*N-1; /* 그림 한 가운데 점의 y 좌표 */
    mx = 2*N-2; /* 그림 한 가운데 점의 x 좌표 */
    B[my+1][mx] = B[my][mx] = B[my-1][mx] = '*'; /* N=1 일 때 그려지는 부분 그리기 */
    f(2); /* 나머지 부분 그리기 */

    // Control : Output
    int H = 4*N-1, W = 4*N-3; /* 전체 그림의 세로 길이와 가로 길이 */
    for (int i=0; i<H; i++) {
        /* 줄의 공백 제거 <= 출력 형식이 잘못되었습니다의 원인 */
        string line;
        for (int j=0; j<W; j++) {
            line.push_back(B[i][j]);
        } while (line.back() == ' ') line.pop_back();
        cout << line << endl;
    }
}

// Helper Functions
void f(int n)
/* N=n 일 때 그려지는 부분 그리기 */
{
    int sy = my - (2*n-1); /* 시작점(맨 왼쪽 위)의 y 좌표 */
    int sx = mx - (2*n-2); /* 시작점(맨 왼쪽 위)의 x 좌표 */
    /* 4*n-3 은 현재 그려지는 부분의 세로 길이, 4*n-1 은 현재 그려지는 부분의 가로 길이 */
    /* 오른쪽, 아래쪽, 왼쪽, 위쪽 순서로 점을 이동시키며 별표를 찍음 */
    int count[4] = {4*n-3, 4*n-1, 4*n-3, 4*n-1};
    for (int i=0; i<4; i++) {
        int cnt = count[i];
        while (cnt--) {
            B[sy][sx] = '*';
            if (cnt > 0) { sy += dy[i], sx += dx[i]; }
        }
    }

    /* 마무리
     * *****    *****
     * *   *    *
     * *   *    *  **
     * *   * => *   *
     * *   *    *   *
     * *   *    *   *
     * *****    *****
     */
    swap(B[my-(2*n-2)][mx+(2*n-2)], B[my-(2*n-3)][mx+(2*n-3)]);

    /* 전체 그림을 모두 그렸다면 종료 */
    if (n == N) return;
    f(n+1); /* 다음 부분 그리기 */
}

좋은 웹페이지 즐겨찾기