[백준/JAVA] 9944번: NxM 보드 완주하기
📖 문제
https://www.acmicpc.net/problem/9944
💡 풀이 방식
• 백트래킹
1. 값을 입력받으면서 격자 안의 값이 장애물(*)인 경우, 방문 처리하고 방문한 칸의 갯수(cnt)를 1 증가시킨다.
2. 한 칸만 빈 칸인 경우, 해당 케이스의 이동 경로 수는 0이다.
if(cnt == N*M) answer = 0; // 한 칸만 빈 칸인 경우
3. 모든 칸을 탐색하며 방문한 적 없는 점에서,
4방향 탐색을 통해 1) 격자 범위 내에 있고, 2) 방문하지 않은 칸을
이동 처리했다가 안 했다가 하며 이동 경로 수를 구한다. (백트래킹)
for(int i = 0 ; i < N ; i++) {
for(int j = 0 ; j < M ; j++) {
if(visited[i][j]) continue;
for(int d = 0 ; d < 4 ; d++) {
if(!isValid(i + dx[d], j + dy[d])) continue;
visited[i][j] = true;
search(i, j, result, d, cnt);
visited[i][j] = false;
}
}
}
[백트래킹 함수]
- 인자 : x좌표, y좌표, 이동 횟수(result), 방향 번호(dir), 방문 갯수(cnt)
search(int i, int j, int result, int dir, int cnt)
- (종료 조건) 모든 빈 칸을 방문한 경우 > 정답이 -1이거나 이동 횟수가 정답보다 크다면, 정답을 이동 횟수로 갱신한다.
if(cnt == N*M) { // 모든 빈 칸 방문한 경우
if(answer == -1 || answer > result) {
answer = result;
return;
}
}
- 그 외의 경우, 현재 좌표(i,j)에서 현재 이동 방향(dir)으로 이동 가능하다면, 다음 지점에 대해 방문했다가/ 안 했다가 하는 경우의 수를 갱신하며 이동을 진행한다. // 만약 이동할 수 없다면, 방향을 변경한 상태에서 방문 여부를 갱신하며 이동을 진행한다.
int x = i + dx[dir];
int y = j + dy[dir];
if(isValid(x, y)) {
visited[x][y] = true;
search(x, y, result, dir, cnt + 1); // 방문한 킨 갯수 +1
visited[x][y] = true;
}
else { // 방향 변경
for(int d = 0 ; d < 4 ; d++) {
if(d == dir) continue;
int nx = i + dx[d];
int ny = j + dy[d];
if(isValid(nx, ny)) {
visited[nx][ny] = true;
search(nx, ny, result + 1, dir, cnt + 1); // 이동 횟수와 방문한 칸 갯수 +1
visited[nx][ny] = true;
}
}
}
🔺 코드
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
import java.util.*;
import java.io.*;
public class Main {
static int[] dx = {-1,1,0,0};
static int[] dy = {0,0,-1,1};
static int N,M;
static char[][] map;
static boolean[][] visited;
static int answer;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
int idx = 0;
String input = "";
while((input = br.readLine()) != null) {
idx++;
answer = -1;
st = new StringTokenizer(input);
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
map = new char[N][M];
visited = new boolean[N][M];
int result = 1; // 이동 횟수
int cnt = 1; // 방문 개수
for(int i = 0 ; i < N ; i++) {
String str = br.readLine();
for(int j = 0 ; j < M ; j++) {
map[i][j] = str.charAt(j);
if(map[i][j] == '*') { // 장애물인 경우
visited[i][j] = true;
cnt++;
}
}
}
// 한 칸만 빈 칸인 경우
if(cnt == N*M) answer = 0;
for(int i = 0 ; i < N ; i++) {
for(int j = 0 ; j < M ; j++) {
if(visited[i][j]) continue; // 장애물인 경우, pass
for(int d = 0 ; d < 4 ; d++) { // 빈 칸(.)인 경우, 4방향 탐색
if(!isValid(i + dx[d], j + dy[d])) continue;
visited[i][j] = true;
search(i, j, result, d, cnt);
visited[i][j] = false; // 지나온 길 되돌아가기
}
}
}
System.out.println("Case " + idx + ": " + answer);
}
}
// x좌표, y좌표, 이동 횟수, 방향 번호, 방문한 칸 개수
private static void search(int i, int j, int result, int dir, int cnt) {
// [종료 조건] 모든 빈 칸을 방문한 경우
if(cnt == N*M) {
if(answer == -1 || answer > result) {
answer = result;
return;
}
}
int x = i + dx[dir];
int y = j + dy[dir];
if(isValid(x, y)) {
visited[x][y] = true;
search(x, y, result, dir, cnt + 1);
visited[x][y] = false; // 지나온 길 되돌아가기
}
else { // 방향 변경
for(int d = 0 ; d < 4 ; d++) {
if(d == dir) continue;
int nx = i + dx[d];
int ny = j + dy[d];
if(isValid(nx, ny)) {
visited[nx][ny] = true;
search(nx, ny, result + 1, d, cnt + 1);
visited[nx][ny] = false; // 지나온 길 되돌아가기
}
}
}
}
private static boolean isValid(int x, int y) {
if(x < 0 || x >= N || y < 0 || y >= M) // 보드 범위를 벗어난 경우
return false;
if(visited[x][y]) // 이미 방문한 경우
return false;
return true;
}
}
|
cs |
➕ 다른 풀이 방식
- 백트래킹 함수 부분이 좀 다르다. 한 쪽 방향으로 계속 진행하다가 다음 방향으로 넘어가고 이런 식으로 하게 하셨다.
[BOJ 9944] NxM 보드 완주하기 (Java)
BOJ 9944 NxM 보드 완주하기재밌는(쉽게 풀리는...) 백트래킹 문제였다.
velog.io
- 상하좌우 방문하지 않는 최대 위치를 반환하는 메소드를 일일이 구현하셨다. (비추)
[Java] 백준 9944 (NxM 보드 완주하기) Gold 3
Problem : https://www.acmicpc.net/problem/9944 9944번: NxM 보드 완주하기 N×M 보드 위에서 할 수 있는 게임이 있다. 보드는 크기가 1×1인 정사각형 칸으로 나누어져 있다. 보드의 각 칸은 빈 칸 또는 장애물이
gre-eny.tistory.com
- 이 코드가 내가 제출한 코드랑 비슷한데 개인적으로는 이해하기 좀 더 좋았던 듯,,✅
[백준] G3 9944 NxM 보드 완주하기 (java)
www.acmicpc.net/problem/9944 9944번: NxM 보드 완주하기 N×M 보드 위에서 할 수 있는 게임이 있다. 보드는 크기가 1×1인 정사각형 칸으로 나누어져 있다. 보드의 각 칸은 빈 칸 또는 장애물이다. 장애물은
laugh4mile.tistory.com
💦 어려웠던 점
- BFS로 풀 생각을 했지, 백트래킹 쓸 생각은 하지 못 했다.
- 입력이 언제 끝날줄 알고 N과 M입력은 어떻게 받지?의 문제
🧐 새로 알게 된 내용
- 해당 칸을 방문하고 길을 되돌아가기 위해 백트래킹으로 푸는 문제라고 이해했다.
- TC개수 정해지지 않고, while문으로 조건 만족 시 계속 작동하도록 하는 방법
1회독 | 2회독 | 3회독 | 4회독 | 5회독 |
V |
(참고)
[Baekjoon] 9944_NxM 보드 완주하기
Gold III 문제(출처: https://www.acmicpc.net/problem/9944) < NxM 보드 완주하기 > 문제 풀이 이동하려는 곳을 미리 확인한 후 보드 범위 밖이거나 이미 방문한 곳이라면 방향을 바꾸도록 구현했다. 종료 조건
melody-coding.tistory.com