문제
2차 세계 대전에서 연합군과 독일군의 전투가 점점 치열해지고 있다.
전투가 진행중인 지역은 대규모 폭격과 시가전 등으로 인해 도로 곳곳이 파손된 상태이다.
그림 1(a)에서와 같이 도로들은 전투로 인해 트럭이나 탱크와 같은 차량들이 지날 갈 수 없다.
전투에서 승리하기 위해서는 기갑사단과 보급부대가 신속하게 이동하기 위한 도로가 있어야 한다.
공병대는 출발지(S) 에서 도착지(G)까지 가기 위한 도로 복구 작업을 빠른 시간 내에 수행하려고 한다.
도로가 파여진 깊이에 비례해서 복구 시간은 증가한다.
출발지에서 도착지까지 가는 경로 중에 복구 시간이 가장 짧은 경로에 대한 총 복구 시간을 구하시오.
깊이가 1이라면 복구에 드는 시간이 1이라고 가정한다.
그림 1 (a) 파손된 도로 (b) 지도 형태와 이동 방향
지도 정보는 그림1(b)와 같이 2차원 배열 형태로 표시된다.
출발지는 좌상단의 칸(S)이고 도착지는 우하단의 칸(G)가 된다.
이동 경로는 상하좌우 방향으로 진행할 수 있으며, 한 칸씩 움직일 수 있다.
지도 정보에는 각 칸마다 파여진 도로의 깊이가 주어진다. 현재 위치한 칸의 도로를 복구해야만 다른 곳으로 이동할 수 있다.
그림 2 지도 정보
이동하는 시간에 비해 복구하는데 필요한 시간은 매우 크다고 가정한다.
따라서, 출발지에서 도착지까지 거리에 대해서는 고려할 필요가 없다.
지도 정보는 그림2에서 보듯이 2차원 배열의 형태이다.
출발지(S)와 도착지(G)는 좌상단과 우하단이 되고 입력 데이터에서는 0으로 표시된다.
출발지와 도착지를 제외한 곳이 0인 것은 복구 작업이 불필요한 곳이다.
다음과 같은 지도에서 복구 작업 시간이 최소인 시간은 2이고 회색으로 칠해진 경로가 된다.
풀이방법
너비우선탐색(BFS, Breadth First Search)를 이용해 해결한다.
너비우선탐색으로 최단 경로를 찾는데 한 가지 경우를 고려해주어여한다.
방문했던 노드라도 새로운 최단경로가 있다면 재탐색해야되는 점이다.
예를 들어 아래와 같은 입력이 주어졌을 때,
0 | 3 | 0 |
5 | 4 | 2 |
4 | 1 | 0 |
(0,0)을 시작으로 같은 레벨의 노드로 너비 우선탐색을 시작한다.
0 | 3 | |
5 | ||
(0,0)에 인접한 노드((1,0), (0,1))를 방문하고 큐에 담는다.
0 | 3 | |
5 | 9 | |
9 |
(1,0)에 인접한 노드((2,0), (1,1))를 방문하고 큐에 담는다.
0 | 3 | 3 |
5 | 7 | |
9 |
이 때, (1,1)의 값이 변하게 된다.
위의 사이클에서 이미 (1,1)를 방문했지만, (1,1)은 (1,0)와도 인접하기 때문이다.
이 경우 (1,1)에는 인접한 두 노드를 경유하는 길이 중 더 짧은 값이 들어가게 된다. 즉, (1,1)은 9에서 7로 바뀌게 된다.
값이 바뀌게된 노드는 전차가 상, 하, 좌, 우로 이동할 수 있기 때문에 경로의 길이가 바뀔 수 있으므로 재탐색을 해주어야한다.
따라서 큐에 다시 넣어 탐색한다.
소스코드
package samsung;
import java.util.*;
public class s_1249 {
public static class Node{
int x;
int y;
Node(int x, int y){
this.x = x;
this.y = y;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int tc = sc.nextInt();
int[] dx = {-1, 0, 1, 0};
int[] dy = {0, 1, 0, -1};
for(int t = 1; t <= tc; t++) {
int n = sc.nextInt();
int[][] a = new int[n][n];
int[][] v = new int[n][n];
int[][] r = new int[n][n];
Queue <Node> q = new LinkedList<>();
for(int i = 0; i < n; i++) {
String s = sc.next();
for(int j = 0; j < n; j++) {
a[i][j] = s.charAt(j) - '0';
r[i][j] = -1;
}
}
r[0][0] = 0;
v[0][0] = 1;
q.add(new Node(0, 0));
while(!q.isEmpty()) {
Node node = q.poll();
int x = node.x;
int y = node.y;
for(int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if(nx >= 0 && ny >= 0 && nx < n && ny < n) {
if(v[nx][ny] == 0) {
q.add(new Node(nx, ny));
v[nx][ny] = 1;
r[nx][ny] = r[x][y] + a[nx][ny];
}
else {
if(r[x][y] + a[nx][ny] < r[nx][ny]) {
r[nx][ny] = r[x][y] + a[nx][ny];
q.add(new Node(nx, ny));
}
}
}
}
}
System.out.println("#" + t + " " + r[n-1][n-1]);
}
}
}
'Problem Solving > SWEA' 카테고리의 다른 글
[SWEA] 1210. [S/W 문제해결 기본] 2일차 - Ladder1 (0) | 2020.03.06 |
---|---|
[SWEA] 1486. 장훈이의 높은 선반 (0) | 2020.03.06 |
[SWEA] 1211. [S/W 문제해결 기본] 2일차 - Ladder2 (0) | 2020.03.05 |
[SWEA] 1218. [S/W 문제해결 기본] 4일차 - 괄호 짝짓기 (0) | 2020.03.05 |
[SWEA] 7829. 보물왕 태혁 (0) | 2020.03.04 |
댓글