/*
* Problem :: 17370 / 육각형 우리 속의 개미
*
* Kind :: DFS + Backtracking
*
* Insight
* - 개미의 현재 위치와 그 위치로 들어온 방향에 따라
* 이동할 수 있는 방향이 달라진다
* + 일단 육각형의 각 꼭짓점에 번호를 매기자
* O <= 1
* / \
* - -
* / \
* O <= 2 O <= 3
* | |
* | |
* O <= 4 O <= 5
* \ /
* - -
* \ /
* O <- 6
* + 위, 아래, 왼쪽, 오른쪽을 각각 U, D, L, R 이라고 하면
* 개미가 이동할 수 있는 방향은 총 6가지다
* UU (4->2, 5->3)
* UR (2->1, 6->5)
* UL (3->1, 6->4)
* DD (2->4, 3->5)
* DR (1->3, 4->6))
* DL (1->2, 5->6)
* # 이를 조합하면,
* 이전 방향 => 다음 가능한 방향 => 실제로 가능한 방향
* UU => UL, UR, DD => UL, UR
* UR => UU, DR, DL => UU, DR
* DR => UR, DD, UL => UR, DD
* DD => DL, DR, UU => DL, DR
* DL => UL, DD, UR => UL, DD
* UL => UU, DL, DR => UU, DL
* 임을 알 수 있다
*
* - 경로를 탐색해야 한다
* + 모든 경로를 탐색해봐도 될까?
* 2^22 = 4194304 < 10^8 이니 시간 제한내에 풀 수 있을 것 같다
* # BFS 로 풀어야 하나, DFS 로 풀어야 하나?
* 모든 경로를 확인해야 되며 그때마다 방문처리를 적절히 해주어야 한다
* 이전의 상태를 쉽게 알 수 있는 DFS 가 적합할 것 같다
* ^= 사실 BFS 로 풀려니 방문처리를 어떻게 다루어야 할지 잘 모르겠다...
* Backtracking 도 BFS 보다는 DFS 가 더 잘 맞는것 같은 느낌이 드는데...
*
* Point
* - max(N)=22 이므로 위아래, 좌우 모두 44 만큼 움직일 수 있다고 생각하여
* 그냥 개미가 움직이는 판을 (bool)isVisited[100][100] 으로 선언했다
* 그러고선 개미는 (50,50) 에서 출발하는 것으로 생각하였다
* 이러면, 개미가 판을 넘어가는 경우는 존재하지 않게 된다
* + 문제 설명에 '무한히 많은 정육각형이 서로 맞닿아 놓인 형태의 개미우리' 라고 적혀져 있으므로
* 개미우리 벽을 넘어가는 유효하지 않은 좌표는 없다
* 따라서 유효한 좌표검사를 신경쓰지 않으려고 개미가 움직이는 판을 크게 잡았다
*
* - 개미가 (50,50) 에서 이전 방향이 UU 인채로 시작한다고 가정하면
* 현재 개미는 (48,50) 을 방문한 것이다
* 따라서 isVisited[48][50] = true 로 설정하는 것을 잊지말자
* + 참고로 좌표계는
* 오른쪽으로 갈수록 x 값이 커지고
* 위쪽으로 갈수록 y 값이 커지는 것으로 설정했다
*/
//
// BOJ
// ver.C++
//
// Created by GGlifer
//
// Open Source
#include <iostream>
using namespace std;
#define endl '\n'
// Set up : Global Variables
int N;
bool isVisited[100][100];
enum Direction { UU, UR, DR, DD, DL, UL }; /* for 가독성 */
int dy[6] = {+2, +1, -1, -2, -1, +1};
int dx[6] = { 0, +2, +2, 0, -2, -2};
int D[6][2] = {
{UL, UR}, /* UU */
{UU, DR}, /* UR */
{UR, DD}, /* DR */
{DL, DR}, /* DD */
{UL, DD}, /* DL */
{UU, DL} /* UL */
};
// Set up : Functions Declaration
int dfs(int cy, int cx, int cnt, int prevDir);
int main()
{
// Set up : I/O
ios::sync_with_stdio(false);
cin.tie(nullptr);
// Set up : Input
cin >> N;
// Process
isVisited[48][50] = true; /* 시작 위치 방문 처리 */
int ans = dfs(50, 50, 0, UU);
// Control : Output
cout << ans << endl;
}
// Helper Functions
int dfs(int cy, int cx, int cnt, int prevDir)
/* 현재 좌표인 (cy, cx) 에서 시작하여 (N-cnt) 만큼 회전하고 멈추는 경우의 수 반환 */
{
/* 현재 좌표가 방문된 좌표이면 */
if (isVisited[cy][cx])
/* 방향 회전을 N번 하였으면 조건에 맞는 경로를 하나 찾았으므로 1을 반환,
* 그렇지 않으면 0을 반환 */
return (cnt == N) ? 1 : 0;
/* 현재 좌표가 방문되지 않은 좌표인데 방향 회전을 N번 이상 하였으면 */
if (cnt >= N)
/* 이 경로는 조건에 맞는 경로가 될 수 없으므로 0을 반환 */
return 0;
isVisited[cy][cx] = true; /* 현재 좌표 방문 처리 */
int ret = 0; /* 경우의 수 */
for (int nextDir : D[prevDir]) {
int ny = cy + dy[nextDir]; /* 탐색할 다음 y 좌표 */
int nx = cx + dx[nextDir]; /* 탐색할 다음 x 좌표 */
ret += dfs(ny, nx, cnt+1, nextDir); /* 경로 탐색 */
}
isVisited[cy][cx] = false; /* 현재 좌표 비(非)방문 처리 */
return ret;
}