어흥

[백준 3678] 카탄의 개척자 (C++) 본문

알고리즘/백준

[백준 3678] 카탄의 개척자 (C++)

라이언납시오 2020. 3. 18. 22:41
728x90
반응형

문제 링크: https://www.acmicpc.net/problem/3678

 

3678번: 카탄의 개척자

문제 "카탄의 개척자"는 많은 사람들이 즐기는 보드게임이다. 게임을 시작하려면, 먼저 게임판을 랜덤으로 만들어야 한다. 게임판은 육각형 타일로 이루어져 있으며, 각 타일은 자원을 하나씩 포함하고 있다. 자원은 총 다섯 가지 종류가 있으며, 점토, 재목, 양모, 곡물, 광석이다. 각 자원은 1부터 5까지 순서로 나타낼 수 있다. 랜덤을 이용해서 게임판을 만들면, 같은 자원이 인접한 타일에 있는 경우가 있을 수도 있다. 이런 배치를 매우 싫어하는 사람이 많다

www.acmicpc.net

1. 주의할 점

- 6각형 형태를 어떻게 나타낼 것인가

  이 부분에 관해서는 백준의 '주사위 윷놀이' 문제와 비슷하다. 어떤 형태로 맵을 나타낼 것인지 떠올리지 못하면 구현 못한다(내 개인적인 생각)

  주사위 윷놀이 링크: https://www.acmicpc.net/problem/17825

 

17825번: 주사위 윷놀이

첫째 줄에 주사위에서 나올 수 10개가 순서대로 주어진다.

www.acmicpc.net

- 규칙을 어떻게 찾을 것인가

- 배열의 범위 계산(y가 x의 2배보다 널널하게 있어야한다)

 

[맵을 어떤 형태로 나타내고 어떤 규칙을 이용할 것인가]  

 1) 맵을 어떤 형태로 나타낼 것인가

  2차 배열을 이용할 예정이다.

  중앙의 육각 타일을 중심으로 다음과 같은 형태를 지니도록 한다.

 

                         y-2,x

 

           y-1,x-1                y-1,x+1

 

                          y,x           

 

           y+1,x-1               y+1,x+1

 

                         y+2,x

 

위와 같은 형태를 지니게 할 경우, 왜 y의 범위를 x의 2배 이상 해야하는지 이해할 수 있다.

또한, 맵을 잘 보면 가운데 시작점을 기준으로 길이가 1,2,3,...,N인 정육각형으로 덮인다.

그렇다면, 길이가 N인 정육각형까지 쌓게 되는 타일의 수는 1+ N*(N-1)/2

1+N*(N-1)/2 <= 10000 를 만족하는 N은 대략 60으로 잡으면된다. 따라서 좌우로 N의 길이만큼 넉넉히 잡으면 300

위아래는 좌우의 2배만큼 필요하므로 600으로 잡는다.

 

 2) 어떤 규칙이 있는가

  1번부터 시작해서 다음 타일을 쌓는 방향을 시침의 방향으로 표현하면 다음과 같다

시작                   -> 길이 1인 정육각형 : 1, 11, 7, 6, 5, 1

길이 1인 정육각형 -> 길이 2인 정육각형:  1, 12, 11, 11, 7, 7, 6, 6, 5, 5, 1, 1

길이 2인 정육각형 -> 길이 3인 정육각형:  1, 12, 12, 11, 11, 11, 7, 7, 7, 6, 6, 6, 5, 5, 5, 1, 1, 1

 

자세히 살펴보면 항상 처음은 1로 시작한다.

그 이후에는 길이 N-1인 정육각형 ->길이 N인 정육각형을 기준으로 12가 N-1개, 11 N개, 7 N개, 6 N개, 5 N개, 1 N개

 

2. 구현

- 위에서 설명한것을 바탕으로 배열의 시작점을 SY = 300, SX = 150으로 시작하고 가장 중앙에 1은 두고 시작한다.

- 다음 타일이 놓일 위치 구하기 -> 해당 위치에 어떤 타일이 올 수 있는가(Check 함수) -> 해당 위치에 타일을 놓았다면 해당 위치에 어떤 타일이 있는지 저장하는 Arr 배열과 몇번 째 타일은 어떤 번호인지 저장하는 Number 배열과 마지막으로 지금까지 사용한 숫자별 타일의 갯수 Num배열에 추가된 타일 번호의 Index에 1을 더한다

- 10000까지 구한 이후, 숫자를 입력받아서 바로 출력한다.

 

#include <iostream>
using namespace std;
int arr[601][301];
int number[10001];
int level = 1, sx = 150, sy = 300, cnt = 1;
int dx[6] = { 0,-1,-1,0,1,1 };
int dy[6] = { -2,-1,1,2,1,-1 };
int num[6] = { 0,1,0,0,0,0 };		//사용한 숫자
bool avail[6];

void check() {
	for (int i = 1; i < 6; i++)
		avail[i] = false;
	//인접한것들 true로 전환
	for (int i = 0; i < 6; i++) {
		int nx = sx + dx[i];
		int ny = sy + dy[i];
		int val = arr[ny][nx];
		if (val != 0) avail[val] = true;
	}
	int maxi = 10000;
	int idx = 0;
	for (int i = 1; i < 6; i++) {
		if (!avail[i]) {				//인접하지 않으면서
			if (num[i] < maxi) {		//사용한 갯수가 가장 적으면서, i값이 작은거
				maxi = num[i];
				idx = i;
			}
		}
	}
	arr[sy][sx] = idx;
	num[idx]++;
	number[++cnt] = idx;
}

void cal() {
	while (level < 61) {
		sx += 1;
		sy -= 1;
		check();
		if (cnt == 10001) break;
		for (int i = 0; i < level - 1; i++) {
			sx += dx[0];
			sy += dy[0];
			check();
			if (cnt == 10001) break;
		}
		for (int k = 1; k <= 5; k++) {
			for (int i = 0; i < level; i++) {
				sx += dx[k];
				sy += dy[k];
				check();
				if (cnt == 10001) break;
			}
		}
		level++;
	}
}

int main() {
	int test, target;
	cin >> test;
	arr[sy][sx] = 1;
	number[1] = 1;
	cal();
	for (int t = 0; t < test; t++) {
		cin >> target;
		cout << number[target] << '\n';
	}
	system("pause");
	return 0;
}
728x90
반응형

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

[백준 13913] 숨바꼭질 4 (C++)  (0) 2020.03.19
[백준 5567] 결혼식 (C++)  (0) 2020.03.19
[백준 1991] 트리 순회 (C++)  (0) 2020.03.18
[백준 2573] 빙산 (C++)  (0) 2020.03.18
[백준 7348] 테이블 옮기기 (C++)  (0) 2020.03.18
Comments