[ 백준 ] 10997 / 별 찍기 - 22
# 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); /* 다음 부분 그리기 */
}
Author And Source
이 문제에 관하여([ 백준 ] 10997 / 별 찍기 - 22), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@gglifer/백준-10997-별-찍기-22
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
/*
* 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 라는 전역변수로 선언해서 사용하였다
*/
//
// 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); /* 다음 부분 그리기 */
}
Author And Source
이 문제에 관하여([ 백준 ] 10997 / 별 찍기 - 22), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@gglifer/백준-10997-별-찍기-22저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)