📕문제
드래건 커브는 다음과 같은 세 가지 속성으로 이루어져 있으며, 이차원 좌표 평면 위에서 정의된다. 좌표 평면의 x축은 → 방향, y축은 ↓ 방향이다.
- 시작 점
- 시작 방향
- 세대
0세대 드래건 커브는 아래 그림과 같은 길이가 1인 선분이다. 아래 그림은 (0, 0)에서 시작하고, 시작 방향은 오른쪽인 0세대 드래건 커브이다.
1세대 드래곤 커브는 0세대 드래건 커브를 끝 점을 기준으로 시계 방향으로 90도 회전시킨 다음 0세대 드래건 커브의 끝 점에 붙인 것이다. 끝 점이란 시작 점에서 선분을 타고 이동했을 때, 가장 먼 거리에 있는 점을 의미한다.
2세대 드래곤 커브도 1세대를 만든 방법을 이용해서 만들 수 있다. (파란색 선분은 새로 추가된 선분을 나타낸다)
3세대 드래곤드래건 커브도 2세대 드래건 커브를 이용해 만들 수 있다. 아래 그림은 3세대 드래건 커브이다.
즉, K(K > 1)세대 드래건 커브는 K-1세대 드래건 커브를 끝 점을 기준으로 90도 시계 방향 회전 시킨 다음, 그것을 끝 점에 붙인 것이다.
크기가 100×100인 격자 위에 드래건 커브가 N개 있다. 이때, 크기가 1 ×1인 정사각형의 네 꼭짓점이 모두 드래건 커브의 일부인 정사각형의 개수를 구하는 프로그램을 작성하시오. 격자의 좌표는 (x, y)로 나타내며, 0 ≤ x ≤ 100, 0 ≤ y ≤ 100만 유효한 좌표이다.
📗입력
첫째 줄에 드래곤 커브의 개수 N(1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 드래건 커브의 정보가 주어진다. 드래건 커브의 정보는 네 정수 x, y, d, g로 이루어져 있다. x와 y는 드래건 커브의 시작 점, d는 시작 방향, g는 세대이다. (0 ≤ x, y ≤ 100, 0 ≤ d ≤ 3, 0 ≤ g ≤ 10)
입력으로 주어지는 드래곤 커브는 격자 밖으로 벗어나지 않는다. 드래건 커브는 서로 겹칠 수 있다.
방향은 0, 1, 2, 3 중 하나이고, 다음을 의미한다.
- 0: x좌표가 증가하는 방향 (→)
- 1: y좌표가 감소하는 방향 (↑)
- 2: x좌표가 감소하는 방향 (←)
- 3: y좌표가 증가하는 방향 (↓)
📗출력
첫째 줄에 크기가 1×1인 정사각형의 네 꼭짓점이 모두 드래건 커브의 일부인 것의 개수를 출력한다.
⚡문제해석
- 방향을 생각해주는 것이 가장 중요한 문제이다.
- 사각형을 체크하는 것은 엄청 쉬운 문제이다.
- 효과적인 자료구조를 사용하는 것이 중요하다.!
🔎문제풀이
방향은 특정한 규칙을 따른다.
끝점을 기준으로 시계방향 90도를 회전시킨다는 말 뜻을 잘 이해해야 한다. [나도 많이 헤맸다.]
이해하기 쉽게 각 세대별 진행정도를 색깔별로 표현해봤습니다.
저도 처음에는 감을 못 잡았는데 이렇게 하나하나 그려보니 규칙이 눈에 보였습니다.
규칙은 바로 이전 세대에 방향을 역순으로 시계방향만큼 90도 회전시켜주는 것입니다.
아래 설명을 보시면 바로 이해가 가실 겁니다.
90도 회전이기에 +1을 하고, %4를 해줘야 합니다. -> 360도를 넘어가면 안 되기 때문입니다.
이렇게 각 세대별로 방향을 특정 지어줬다면 그다음은 굉장히 간단한 문제입니다.
저렇게 지나가는 좌표를 방문처리를 해주고 사각형을 이룬다면 그때 사각형의 개수를 +1 해주면 됩니다.
💻코드
주석을 달아놨는데 궁금한 게 있으면 댓글부탁드립니답🙏
/*
백준 골드4 드래곤 커브
*/
#include <iostream>
#include <vector>
#include <algorithm>
#include <math.h>
#include <stack>
#include <deque>
#include <queue>
using namespace std;
int n, x, y, d, g;
vector<int> Y = {0, -1, 0, 1}; // 실제로 Y좌표ㅕ
vector<int> X = {1, 0, -1, 0}; // 실제로 X좌표
vector<vector<int>> visit;
stack<int> direct;
deque<int> result;
void make_curve();
void square();
int answer = 0;
int main()
{
visit.resize(101, vector<int>(101, 0));
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> x >> y >> d >> g; // x,y는 시작점 d= 방향 g는 세대
make_curve();
square();
}
for (int i = 0; i < 100; i++)
{
for (int j = 0; j < 100; j++)
{
if (visit[i][j] == 1 && visit[i + 1][j] == 1 && visit[i + 1][j + 1] == 1 && visit[i][j + 1] == 1)
{
answer++;
}
}
}
cout << answer;
}
void make_curve()
{
result.push_back(d); //0세대 처리
for (int i = 1; i <= g; i++) //0세대를 위에서 처리했기에 1세대부터 반복문을 들어감.
{
stack<int> temp(result); // temp에다가 result를 복사함.
for (int j = 0; j < pow(2, i - 1); j++) // 세대별로 2^(세대-1)만큼 선이 추가됨.
{
result.push_back((temp.top() + 1) % 4); // 가장 최근에 방향벡터+1 값을 넣어줌.
temp.pop();
}
}
}
void square()
{
while (!result.empty())
{
int dir = result.front();
visit[x][y] = 1;
x += X[dir];
y += Y[dir];
// 계속 꼬리를 무는 식으로 좌표를 기록함.
visit[x][y] = 1;
// 항상 방문한 좌표는 방문처리를 해줌.
result.pop_front();
}
}
✔느낀 점
- 자료구조에 대해서 명확하게 알고 있어야겠다고 생각했습니다.
- 오랜만에 stack을 사용하니 조금 헷갈린 부분이 많았습니다.
- 방향벡터를 기록하고 추가할 때
- 그리고 문제 내에서 방향과 실제 증감하는 값에 혼동이 있어서 굉장히 오래 걸렸습니다.
- 개 어려웠습니다.
'CodingTest > Baekjoon' 카테고리의 다른 글
[백준 16974] - 레벨 햄버거(C++)[실버1] (0) | 2023.01.03 |
---|---|
[백준 2630]- 색종이만들기(C++)[실버2] (0) | 2022.12.31 |
[백준 11559] - Puyo Puyo(C++)[골드4] (0) | 2022.12.26 |
[백준 2469] - 사다리타기(C++) [골드5] (1) | 2022.12.24 |
[백준 4485] - 녹색 옷 입은 애가 젤다지?(C++) (2) | 2022.11.24 |