Note: 해당 알고리즘은 java로 풀이되었습니다.
문제 분석
D2의 난이도고 문제만 읽었을 때는 굉장히 쉬워보이지만 실제로 풀어보면 ‘어?’ 소리가 나는 문제입니다.
물론 간단하게 푸신 분들도 많고요.
푸는 방법은 여러가지가 있습니다. 저 같은 경우에는 DFS로 풀었습니다.
먼저 코드를 보겠습니다.
풀이
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
static int N, T, C;
static int[][] Map;
static boolean[][] isgo;
public static void main(String args[]) throws Exception {
System.setIn(new FileInputStream("res/달팽이_숫자.txt"));
Scanner sc = new Scanner(System.in);
T = sc.nextInt();
for (int test_case = 1; test_case <= T; test_case++) {
N = sc.nextInt();
Map = new int[N][N];
isgo = new boolean[N * 2][N * 2];
C = N * N;
Map[0][0] = 1;
isgo[0][0] = true;
Solution(0, 0, 2);
System.out.println("#" + test_case);
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
System.out.print(Map[i][j] + " ");
}
System.out.println("");
}
}
}
private static void Solution(int r, int c, int cnt) {
if (cnt > C)
return;
for (int i = 1; i <= N; i++) {
if (c + i < N && isgo[r][c + i] == false) {
Map[r][c + i] = cnt;
isgo[r][c + i] = true;
cnt++;
} else {
c = c + i - 1;
break;
}
}
for (int i = 1; i <= N; i++) {
if (r + i < N && isgo[r + i][c] == false) {
Map[r + i][c] = cnt;
isgo[r + i][c] = true;
cnt++;
} else {
r = r + i - 1;
break;
}
}
for (int i = 1; i <= N; i++) {
if (c - i >= 0 && isgo[r][c - i] == false) {
Map[r][c - i] = cnt;
isgo[r][c - i] = true;
cnt++;
} else {
c = c - i + 1;
break;
}
}
for (int i = 1; i <= N; i++) {
if (r - i >= 0 && isgo[r - i][c] == false) {
Map[r - i][c] = cnt;
isgo[r - i][c] = true;
cnt++;
} else {
r = r - i + 1;
break;
}
}
Solution(r, c, cnt);
}
먼저 test case인 T와 map의 크기인 N, 최댓값인 C, 그리고 이미 간 곳인지 확인하는 boolean 배열, isgo를 선언합니다.
그리고 Solution이라는 이름의 DFS 재귀함수를 호출합니다.
private static void Solution(int r, int c, int cnt) {
if (cnt > C)
return;
for (int i = 1; i <= N; i++) {
if (c + i < N && isgo[r][c + i] == false) {
Map[r][c + i] = cnt;
isgo[r][c + i] = true;
cnt++;
} else {
c = c + i - 1;
break;
}
}
for (int i = 1; i <= N; i++) {
if (r + i < N && isgo[r + i][c] == false) {
Map[r + i][c] = cnt;
isgo[r + i][c] = true;
cnt++;
} else {
r = r + i - 1;
break;
}
}
for (int i = 1; i <= N; i++) {
if (c - i >= 0 && isgo[r][c - i] == false) {
Map[r][c - i] = cnt;
isgo[r][c - i] = true;
cnt++;
} else {
c = c - i + 1;
break;
}
}
for (int i = 1; i <= N; i++) {
if (r - i >= 0 && isgo[r - i][c] == false) {
Map[r - i][c] = cnt;
isgo[r - i][c] = true;
cnt++;
} else {
r = r - i + 1;
break;
}
}
Solution(r, c, cnt);
}
재귀 함수를 탈출하는 기저 조건은 cnt값이 최댓값인 C보다 커지는 경우입니다.
그다음에는 사이클을 4가지로 잡았습니다.
먼저 오른쪽으로 끝까지 이동하는 것, 그 다음 아래 왼쪽 위 방향으로 순서대로 끝까지 이동하는 것입니다.
사이클을 다 돌면 다시 그 위치에서 재귀함수를 돌립니다.
후기
재귀함수를 제대로 알고 있다면 크게 어렵지는 않은 문제였습니다.
만약 이 문제가 어려웠다면 재귀함수를 다시 한번 학습해보세요.
만약 코드를 다운 받고 싶다면 공유한 깃허브에 접속해주세요.
오류 지적, 질문, 더 나은 풀이는 언제든지 메일이나 댓글로 부탁드립니다.
감사합니다.