티스토리 뷰
반응형
문제
- 여러 섬으로 이루어진 나라가 있다.
- 이 나라의 대통령은 섬을 잇는 다리를 만들겠다는 공약으로 인기몰이를 해 당선될 수 있었다.
- 하지만 막상 대통령에 취임하자, 다리를 놓는다는 것이 아깝다는 생각을 하게 되었다.
- 그래서 그는, 생색내는 식으로 한 섬과 다른 섬을 잇는 다리 하나만을 만들기로 하였고, 그 또한 다리를 가장 짧게 하여 돈을 아끼려 하였다.
- 이 나라는 N × N 크기의 이차원 평면상에 존재한다.
- 이 나라는 여러 섬으로 이루어져 있으며, 섬이란 동서남북으로 육지가 붙어있는 덩어리를 말한다.
- 다음은 세 개의 섬으로 이루어진 나라의 지도이다.
- 위의 그림에서 색이 있는 부분이 육지이고, 색이 없는 부분이 바다이다.
- 이 바다에 가장 짧은 다리를 놓아 두 대륙을 연결하고자 한다.
- 가장 짧은 다리란, 다리가 격자에서 차지하는 칸의 수가 가장 작은 다리를 말한다.
- 다음 그림에서 두 대륙을 연결하는 다리를 볼 수 있다.
- 물론 위의 방법 외에도 다리를 놓는 방법이 여러 가지 있으나, 위의 경우가 놓는 다리의 길이가 3으로 가장 짧다 (물론 길이가 3인 다른 다리를 놓을 수 있는 방법도 몇 가지 있다).
- 지도가 주어질 때, 가장 짧은 다리 하나를 놓아 두 대륙을 연결하는 방법을 찾으시오.
입력
- 첫 줄에는 지도의 크기 N(100이하의 자연수)가 주어진다.
- 그 다음 N줄에는 N개의 숫자가 빈칸을 사이에 두고 주어지며, 0은 바다, 1은 육지를 나타낸다.
- 항상 두 개 이상의 섬이 있는 데이터만 입력으로 주어진다.
출력
- 첫째 줄에 가장 짧은 다리의 길이를 출력한다.
솔루션
- 먼저 BFS를 수행하여 대륙마다 각각 다른 번호를 지정해준다.
- 예를 들면, 첫 번째 대륙은 2, 두 번째 대륙은 3
- 대륙에 번호를 지정함과 동시에 대륙의 좌표 정보를 모은다.
- 대륙에 번호를 지정하고 난 다음, 다리 건설을 시작한다.
- 위에서 모은 대륙 좌표 정보를 모두 큐에 집어넣고 현재 큐 크기를 변수에 담아 이 값만큼 반복을 수행한다.
- 각 좌표에서 부터 BFS를 수행한다.
- 바다 (좌표 값이 0) 를 만났을 경우, 방문 여부를 확인한다.
- 현재 바다를 방문한 적이 있다면, 다른 좌표로 넘어가 다시 BFS를 수행한다.
- 현재 바다를 방문한 적이 없다면, 방문 표시를 하고 큐에 해당 바다 좌표 정보를 삽입한다.
- 대륙을 만났을 경우, 대륙 번호를 확인한다.
- 대륙 번호가 같다면, 동일한 대륙이므로 다시 BFS를 수행한다.
- 대륙 번호가 같지 않다면, 다른 대륙에 도착한 것이므로 현재 다리길이 값을 반환한다.
- 바다 (좌표 값이 0) 를 만났을 경우, 방문 여부를 확인한다.
- 반복문을 수행하고 나오면 아직 대륙을 찾지 못한 것이므로, 다리길이를 1 증가시키고 다시 처음부터 수행한다.
- 각 좌표에서 부터 BFS를 수행한다.
- 위에서 모은 대륙 좌표 정보를 모두 큐에 집어넣고 현재 큐 크기를 변수에 담아 이 값만큼 반복을 수행한다.
- 핵심은 다리 건설을 시작할 때 큐에 정보들을 집어넣고 현재 큐 크기만큼 반복문을 수행하는 것이 아니라 처음 큐 크기를 따로 담은 뒤 정해진 그 크기만큼 수행한다는 것이다.
- 이 반복문 없이 그냥 수행한다면 한쪽방향으로 계속 진행하는 경우가 있을 수 있고, 결국 대륙에 도달했지만 이 최소 값이 아닌 값을 가지고 다리 건설 과정이 종료된다.
- 그림을 통해 보자.
- 처음 대륙에 숫자 지정 작업을 끝내고, 다리를 건설한다고 해보자.
- 그러면 큐에는 아래 빨간색 점들의 정보가 들어가 있을 것이다.
- 처음 대륙에 숫자 지정 작업을 끝내고, 다리를 건설한다고 해보자.
- 여기서 다리를 건설하기 위해 저 개수만큼 BFS를 수행한다.
- 그러면 큐에는 위 정보들이 빠져나올거고 아래와 같은 좌표 정보들이 담길 것이다.
- 마찬가지로 위와 동일하게 현재 담긴 큐 크기 (위 빨간색 좌표) 만큼 다리 건설을 수행하면 아래와 같은 정보들로 바뀐다.
- 위와 같은 수행을 다른 대륙을 만날 때까지 진행하면 최종적으로 현재 대륙에서 다른 대륙으로 가기 위해 필요한 최소 다리길이를 얻을 수 있다.
- 반복문이 없다면 동일하게 한 칸씩 진행되는 것이 아닌 어느 부분에서는 그 진행방향이 최소 다리길이를 구하는 곳이 아니더라도 두 칸, 세 칸 먼저 진행되어 대륙에 먼저 도달할 수도 있다.
- 이 작업들을 현재 대륙 뿐만 아니라 다른 대륙에 대해서도 동일하게 수행하여 최소 다리길이를 얻은 다음, 이전에 얻었던 최소 다리길이와 비교하여 값을 갱신하거나 기존 값을 유지하는 것이다.
Code
- 전체 코드 : Solution_2146
대륙 번호 매기기
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
|
public static void NumberingContinent(int x, int y, int num, LinkedList<Point> conti) {
Queue<Point> queue = new LinkedList<>();
visited[x][y] = true;
map[x][y] = num;
queue.offer(new Point(x, y));
conti.add(new Point(x, y));
while (!queue.isEmpty()) {
Point cur = queue.poll();
for (int i = 0; i < 4; i++) {
int nx = cur.x + dx[i];
int ny = cur.y + dy[i];
if (0 <= nx && nx < N && 0 <= ny && ny < N) {
if (!visited[nx][ny] && map[nx][ny] == 1) {
queue.offer(new Point(nx, ny));
visited[nx][ny] = true;
map[nx][ny] = num;
conti.add(new Point(nx, ny));
}
}
}
}
}
|
cs |
다리 만들기
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
|
public static int ConstructingBridge(LinkedList<Point> conti, int num) {
int bridge = 0;
Queue<Point> queue = new LinkedList<>();
queue.addAll(conti);
while (!queue.isEmpty()) {
int continum = queue.size();
for (int k = 0; k < continum; k++) {
Point cur = queue.poll();
for (int i = 0; i < 4; i++) {
int nx = cur.x + dx[i];
int ny = cur.y + dy[i];
if (0 <= nx && nx < N && 0 <= ny && ny < N) {
if(map[nx][ny] == 0) {
if(!visited[nx][ny]) {
queue.offer(new Point(nx, ny));
visited[nx][ny] = true;
}
} else if(map[nx][ny] != num)
return bridge;
}
}
}
bridge++;
}
return bridge;
}
|
cs |
결과
반응형
'Algorithm > Solution' 카테고리의 다른 글
[백준 1261] - 알고스팟 (0) | 2020.03.09 |
---|---|
[백준 3055] - 탈출 (0) | 2020.03.08 |
[백준 1475] - 방 번호 (0) | 2020.03.05 |
[백준 2504] - 괄호의 값 (2) | 2020.03.04 |
[프로그래머스] - 쇠막대기 (0) | 2020.03.04 |
댓글