[백준 15684 : JAVA] 사다리 조작 / 백트래킹
문제
풀이
개인적으로 되게 어려웠던 문제였다. 풀이를 보면서도 많은 시간 고민했다.
첫 번째로 고민했던건 주어지는 가로선의 정보를 어떤 식으로 저장할까였다.
그동안 풀었던 문제는 대게 칸으로 주어졌기 때문에 별 생각없이 map[y][x] 에 저장하면 됬지만, y축과 x축이 칸이 아닌 선으로 주어져서 고민했는데, 그냥 아래처럼 칸이라 생각하고 똑같이 저장하면 되겠다라고 생각이 들었다.
위의 그림에서 최상단 좌측을 (1, 1)이라 두고, 값이 저장되는 세 가지 경우를 나눴다.
0 : 해당 칸에는 가로선이 없다.
1 : 해당 칸을 기준으로 우측으로 연결되는 가로선이 있다.
2 : 해당 칸을 기준으로 좌측으로 연결되는 가로선이 있다.
1번 높이의 1번과 2번 세로선을 연결하는 가로선이 있다면, map[1][1] = 1; map[1][2] = 2; 이런 식으로 저장했다.
그런 다음 i번에서 출발해 i번에 도착하는지 확인하는 체크 용도의 함수가 필요한데, 아래와 같은 코드로 체크했다.
private static boolean check() {
for (int i = 1; i <= width; i++) {
int nx = i;
int ny = 1;
while (ny <= height) {
if (map[ny][nx] == 1) nx++; // 우측으로 이동
else if (map[ny][nx] == 2) nx--; // 좌측으로 이동
ny++; // y축+1칸 이동한다. (아래로 이동)
}
if (nx != i) return false; // i번으로 출발해서 i번으로 도착하지 않는게 하나라도 있다면 리턴.
}
return true;
}
마지막으로 DFS 탐색의 파라미터로 추가할 가로선의 수를 지정해줘야한다. 이게 DFS 탐색의 종료 조건이 되기 때문이다.
최대 3개의 가로선을 추가할 수 있으므로, 이를 반복문으로 놔두고 각 내부에서 DFS를 호출하는 방법을 이용했다.
코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
private static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
private static int width, height, M, ans;
private static int[][] map;
private static boolean isFinish = false;
public static void main(String[] args) throws IOException {
StringTokenizer st = new StringTokenizer(br.readLine());
width = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken()); // 연결된 가로선의 갯수
height = Integer.parseInt(st.nextToken());
map = new int[height + 1][width + 1];
for (int y = 0; y < M; y++) {
st = new StringTokenizer(br.readLine());
// a 높이에서 b번과 b+1번 세로선을 연결한다.
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
map[a][b] = 1; // 1 : 우측으로 이동.
map[a][b + 1] = 2; // 2 : 좌측으로 이동.
}
// 추가할 가로선의 갯수를 미리 정해놔야 탐색 종료 조건으로 걸 수 있다.
// 아래 반복문에서 i는 추가할 가로선의 수.
for (int i = 0; i <= 3; i++) {
ans = i;
dfs(1, 1, 0);
if (isFinish) break;
}
System.out.println((isFinish ? ans : -1));
br.close();
}
// addHorizontalLineNumber : 추가한 가로선의 갯수 (3개가 넘어가면 더이상의 탐색이 무의미.)
private static void dfs(int x, int y, int addHorizontalLineNumber) {
if (isFinish) return;
if (ans == addHorizontalLineNumber) {
if (check()) isFinish = true;
return;
}
for (int i = y; i <= height; i++) {
for (int j = x; j < width; j++) {
// 가로선 두 개가 연속으로 놓여질 수 없기 때문에 가로선을 추가하기 전에 연결된 가로선이 있는지 확인한다.
if (map[i][j] == 0 && map[i][j + 1] == 0) {
// 가로선을 추가한다.
map[i][j] = 1;
map[i][j + 1] = 2;
dfs(1, 1, addHorizontalLineNumber + 1);
// 추가했던 가로선을 다시 제거한다. (백트래킹)
map[i][j] = 0;
map[i][j + 1] = 0;
}
}
}
}
// i번으로 출발해서 i번으로 도착하는지 확인한다.
private static boolean check() {
for (int i = 1; i <= width; i++) {
int nx = i;
int ny = 1;
while (ny <= height) {
if (map[ny][nx] == 1) nx++; // 우측으로 이동
else if (map[ny][nx] == 2) nx--; // 좌측으로 이동
ny++; // y축+1칸 이동한다. (아래로 이동)
}
if (nx != i) return false; // i번으로 출발해서 i번으로 도착하지 않는게 하나라도 있다면 리턴.
}
return true;
}
}
'Algorithm > Baekjoon' 카테고리의 다른 글
[백준 1339 : JAVA] 단어 수학 / 백트래킹 (0) | 2020.11.09 |
---|---|
[백준 2529 : JAVA] 부등호 / 백트래킹 (0) | 2020.11.08 |
[백준 6549 : JAVA] 히스토그램에서 가장 큰 직사각형 / 세그먼트 트리 +분할정복 (0) | 2020.11.02 |
[백준 2842 : JAVA] 집배원 한상덕 / BFS + 투 포인터 (0) | 2020.10.27 |
[백준 2531 : JAVA] 회전 초밥 / 투 포인터 (0) | 2020.10.26 |
댓글
이 글 공유하기
다른 글
-
[백준 1339 : JAVA] 단어 수학 / 백트래킹
[백준 1339 : JAVA] 단어 수학 / 백트래킹
2020.11.09 -
[백준 2529 : JAVA] 부등호 / 백트래킹
[백준 2529 : JAVA] 부등호 / 백트래킹
2020.11.08 -
[백준 6549 : JAVA] 히스토그램에서 가장 큰 직사각형 / 세그먼트 트리 +분할정복
[백준 6549 : JAVA] 히스토그램에서 가장 큰 직사각형 / 세그먼트 트리 +분할정복
2020.11.02 -
[백준 2842 : JAVA] 집배원 한상덕 / BFS + 투 포인터
[백준 2842 : JAVA] 집배원 한상덕 / BFS + 투 포인터
2020.10.27