[DRAGON] 문제 😊😊😊😊😊
드래곤 커브(Dragon curve)는 간단한 수학 규칙으로 그릴 수 있는 그림으로, 위 그림같은 형태를 지닙니다. 드래곤 커브는 선분 하나에서 시작해서 간단한 규칙으로 이 선분을 변형해서 만들어지며, 변형이 한 번 이루어져 세대가 변할 때마다 더욱 복잡한 모양으로 진화합니다. 이 도형같이 일부를 확대했을 때 전체와 비슷한 형태로 구성된 도형들을 프랙탈(fractal) 이라고 하지요.
드래곤 커브를 그리는 방법을 드래곤 커브 문자열이라고 부릅시다. 드래곤 커브 문자열은 X, Y, F, +, -로 구성된 문자열인데, 우리는 한 점에서 시작해 다음과 같이 커브를 그리면 됩니다.
- F: 앞으로 한 칸 전진하며 선을 긋습니다.
- +: 왼쪽으로 90도 회전합니다.
- -: 오른쪽으로 90도 회전합니다.
- X, Y: 무시합니다.
0세대 드래곤 커브를 그리는 문자열은 선분 하나인 FX 입니다. 그리고 그 이후의 다음 세대는 이전 세대 문자열의 각 글자를 다음과 같이 치환해서 만들어집니다.
- X => X+YF
- Y => FX-Y
따라서 1, 2세대 드래곤 커브 문자열은 다음과 같습니다.
- 1세대: FX+YF
- 2세대: FX+YF+FX-YF
n세대 드래곤 커브 문자열을 구하고 싶습니다. 이 때 문자열 전체를 구하면 너무 기니, 문자열 중 p번째 글자부터 l글자만을 계산하는 프로그램을 작성하세요.
입력
입력의 첫 줄에는 테스트 케이스의 수 c (c <=50) 가 주어집니다. 각 테스트 케이스의 첫 줄에는 세 개의 정수로 드래곤 커브의 세대 n (0 <= n <= 50) , 그리고 p 와 l (1 <= p <= 1,000,000,000 , 1 <= l <= 50) 이 주어집니다. n세대의 드래곤 커브 문자열의 길이는 항상 p+l 이상이라고 가정해도 좋습니다.
출력
각 테스트케이스마다 한 줄에 n세대 드래곤 커브 문자열의 p번째 글자부터 l글자를 출력합니다.
입력 예제
4
0 1 2
1 1 5
2 6 5
42 764853475 30
출력 예제
FX
FX+YF
+FX-Y
FX-YF-FX+YF+FX-YF-FX+YF-FX-YF-
전체 코드는 다음과 같습니다.
//
// DRAGON.cpp
// AALGGO
//
// Created by inhyeok on 2021/10/11.
//
#include <iostream>
#include <fstream>
#include <algorithm>
#include <assert.h>
#include <string>
using namespace std;
ifstream fin("DRAGON.txt");
const int MAX = 1000000000 + 1;
int length[51];
int n; // n세대 드래곤 커브
int p; // 문자열의 p 번째 글자부터
int l; // l번쨰 글자 까지.
void precalc(){
length[0] = 1;
for(int i=1; i<= 50; i++)
length[i] = min(MAX, 2*length[i-1] + 2);
}
const string EXPAND_X = "X+YF";
const string EXPAND_Y = "FX-Y";
// Dragon 을 generaion 진화 시킨 상태에서 skip번째 문자열을 출력한다.
char expand(const string& Dragon, int generation, int skip){
//기저 사례
if(generation == 0){
assert(skip < Dragon.size()); // 드래곤 길이 보다 찾으려는 위치가 작으면 종료.
return Dragon[skip];
}
for(int i=0; i< Dragon.size(); i++){
//문자열이 확장되는 경우
if(Dragon[i] == 'X' || Dragon[i]== 'Y'){
if(skip >= length[generation])
skip -= length[generation];
else if(Dragon[i]=='X')
return expand(EXPAND_X, generation-1, skip);
else
return expand(EXPAND_Y, generation-1, skip);
}
//확장되지 않고 건너 뛰어야 할 경우
else if(skip>0){
--skip;
}
else
return Dragon[i];
}
return '*';
}
int main(int argc, const char * argv[]) {
int test_case;
fin >> test_case;
precalc();
for(int i = 0; i < test_case; i++){
fin >> n >> p >> l;
for(int j=0; j< l; j++)
cout << expand("FX", n, p+j-1);
cout << endl;
}
return 0;
}
Comments