Algorithm/백준(BOJ)
[백준] 16197. 두 동전 (Java)
Carroti
2022. 12. 10. 03:27
문제
16197번: 두 동전
N×M 크기의 보드와 4개의 버튼으로 이루어진 게임이 있다. 보드는 1×1크기의 정사각형 칸으로 나누어져 있고, 각각의 칸은 비어있거나, 벽이다. 두 개의 빈 칸에는 동전이 하나씩 놓여져 있고,
www.acmicpc.net
알고리즘
깊이우선탐색(DFS), 백트래킹
풀이
깊이우선탐색을 통해 상하좌우 네 방향으로 동전을 이동시키며 모든 경우를 탐색해 최소 횟수를 찾는다.
아이디어는 다음과 같다.
1. 동전의 위치를 보드 배열에 'o' 로 표시하는게 아니라 (y1,x1) (y2,x2) 좌표로 관리한다.
보드 배열을 수정하지 않음으로써 구현을 편하게 할 수 있다.
2. [N+2][M+2] 크기의 배열을 선언하여 테두리는 초기화된 0 그대로 두고, 그 안쪽 [N][M] 크기만 입력으로 주어진 보드대로 입력받는다.
board[y1][x1] 혹은 board[y2][x2] 가 0 이라면 각 동전이 보드에서 떨어진 것임을 알 수 있다.
3. 버튼을 누른 횟수, 각 동전의 좌표를 매개변수로 깊이우선탐색을 진행한다.
만약 버튼을 누른 횟수가 10을 넘거나, 두 동전이 모두 떨어졌다면 탐색을 중단한다.
if (count > 10 || (board[y1][x1] == 0 && board[y2][x2] == 0)) return;
만약 하나의 동전만 떨어졌다면 최솟값을 갱신하고 탐색을 중단한다.
if ((board[y1][x1] == 0 && board[y2][x2] != 0) || (board[y1][x1] != 0 && board[y2][x2] == 0)) {
min = Math.min(min, count);
return;
}
만약 하나의 동전도 떨어지지 않았다면 상하좌우로 탐색을 계속 진행한다.
for (int i = 0; i < dy.length; i++) {
int ny1 = y1 + dy[i];
int nx1 = x1 + dx[i];
int ny2 = y2 + dy[i];
int nx2 = x2 + dx[i];
if (board[ny1][nx1] == '#') {
ny1 = y1;
nx1 = x1;
}
if (board[ny2][nx2] == '#') {
ny2 = y2;
nx2 = x2;
}
dfs(count + 1, ny1, nx1, ny2, nx2);
}
4. 탐색을 마친 뒤 최솟값이 한번도 갱신되지 않았다면 -1을 출력하고 그렇지 않다면 갱신된 최솟값을 출력한다.
코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
static int[] dy = { -1, 1, 0, 0 };
static int[] dx = { 0, 0, -1, 1 };
static int min;
static char[][] board;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine(), " ");
int N = Integer.parseInt(st.nextToken());
int M = Integer.parseInt(st.nextToken());
board = new char[N + 2][M + 2];
int[][] coin = new int[2][2];
int index = 0;
for (int i = 1; i <= N; i++) {
String str = br.readLine();
for (int j = 1; j <= M; j++) {
if (str.charAt(j - 1) == 'o') {
coin[index][0] = i;
coin[index][1] = j;
index++;
board[i][j] = '.';
} else {
board[i][j] = str.charAt(j - 1);
}
}
}
min = Integer.MAX_VALUE;
dfs(0, coin[0][0], coin[0][1], coin[1][0], coin[1][1]);
System.out.println(min == Integer.MAX_VALUE ? -1 : min);
}
private static void dfs(int count, int y1, int x1, int y2, int x2) {
if (count > 10 || (board[y1][x1] == 0 && board[y2][x2] == 0))
return;
if ((board[y1][x1] == 0 && board[y2][x2] != 0) || (board[y1][x1] != 0 && board[y2][x2] == 0)) {
min = Math.min(min, count);
return;
}
for (int i = 0; i < dy.length; i++) {
int ny1 = y1 + dy[i];
int nx1 = x1 + dx[i];
int ny2 = y2 + dy[i];
int nx2 = x2 + dx[i];
if (board[ny1][nx1] == '#') {
ny1 = y1;
nx1 = x1;
}
if (board[ny2][nx2] == '#') {
ny2 = y2;
nx2 = x2;
}
dfs(count + 1, ny1, nx1, ny2, nx2);
}
}
}