티스토리 뷰
문제 링크 : https://www.acmicpc.net/problem/2146
문제
여러 섬으로 이루어진 나라가 있다. 이 나라의 대통령은, 섬들을 잇는 다리를 만들겠다는 공약으로 인기몰이를 해 당선될 수 있었다. 하지만 막상 대통령에 취임하자, 다리를 놓는다는 것이 아깝다는 생각을 하게 되었다. 그래서 그는, 생색내는 식으로 한 섬과 다른 섬을 잇는 다리 하나만을 만들기로 하였고, 그 또한 다리를 가장 짧게 하여 돈을 아끼려 하였다.
이 나라는 N×N크기의 이차원 평면상에 존재한다. 이 나라는 여러 섬으로 이루어져 있으며, 섬이란 동서남북으로 육지가 붙어있는 덩어리를 말한다. 다음은 세 개의 섬으로 이루어진 나라의 지도이다.
위의 그림에서 색이 있는 부분이 육지이고, 색이 없는 부분이 바다이다. 이 바다에 가장 짧은 다리를 놓아 두 대륙을 연결하고자 한다. 가장 짧은 다리란, 다리가 격자에서 차지하는 칸의 수가 가장 작은 다리를 말한다. 다음 그림에서 두 대륙을 연결하는 다리를 볼 수 있다.
물론 위의 방법 외에도 다리를 놓는 방법이 여러 가지 있으나, 위의 경우가 놓는 다리의 길이가 3으로 가장 짧다(물론 길이가 3인 다른 다리를 놓을 수 있는 방법도 몇 가지 있다).
지도가 주어질 때, 가장 짧은 다리 하나를 놓아 두 대륙을 연결하는 방법을 찾으시오.
입력
첫 줄에는 지도의 크기 N(100이하의 자연수)가 주어진다. 그 다음 N줄에는 N개의 숫자가 빈칸을 사이에 두고 주어지며, 0은 바다, 1은 육지를 나타낸다. 항상 두 개 이상의 섬이 있는 데이터만 입력으로 주어진다.
출력
첫째 줄에 가장 짧은 다리의 길이를 출력한다.
풀이
다리를 최소로 만드면서 동시에 다리를 연결시키는게 이문제의 목적이다. 다리를 두기 위해서는 서로 다른 육지를 구분해줄 필요가 있다. 그러기 위해서 육지 번호를 새겨주는 함수가 필요했다. Queue를 이용하여 육지 번호를 구분해주었다.
육지를 구분해준 이후에 육지의 각 지점 각각을 기준으로하여 그 지점으로부터 다리를 하나씩 만들 때 다리가 처음 다른 육지를 만나는 순간 그 값을 Min이라는 값에 넣어주었다. 다리를 최소를 두는 게 목적이므로 다른 육지로 올 때까지 만든 다리의 개수가 Min에 저장돼있는 값보다 크다면 그 값은 걸러준다.
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
void CurveNum() ;
int N;
int map[101][101];
int visited[101][101];
int vety[]={1,0,-1,0};
int vetx[]={0,1,0,-1};
int seq = 1 ;
queue<pair<int , int > > q;
//다리에 단어 새기기
void CurveNum() {
int i;
while(!q.empty()) {
int cury = q.front().first;
int curx = q.front().second;
q.pop();
for( i = 0 ; i<4; i++) {
int nextx = curx + vetx[i];
int nexty = cury + vety[i];
if( nextx >=1 && nextx<=N && nexty >=1 && nexty<=N) {
if(map[nexty][nextx] == 1 && visited[nexty][nextx] == 0) {
visited[nexty][nextx] = 1 ;
map[nexty][nextx] =seq;
q.push({nexty,nextx});
}
}
}
}
}
//최단거리 구하기
int Min = 987654321;
void BFS(int Num) {
int i ;
while(!q.empty()) {
int cury = q.front().first;
int curx = q.front().second;
q.pop();
if(Min < visited[cury][curx]) {
while(!q.empty())
q.pop();
return;
}
for( i = 0 ;i<4; i++) {
int nextx = curx + vetx[i];
int nexty = cury + vety[i];
if(nextx >=1 && nextx <= N && nexty >=1 && nexty <=N ) {
if( map[nexty][nextx] != Num && map[nexty][nextx]!=0 ) {
if(Min > visited[cury][curx])
Min = visited[cury][curx];
} else if( map[nexty][nextx] == 0 && visited[nexty][nextx] == 0 ) {
visited[nexty][nextx] = visited[cury][curx] + 1;
q.push({nexty,nextx});
}
}
}
}
}
int main()
{
int i,j;
cin >> N;
for( i =1; i<= N ; i++)
for( j = 1; j<=N ; j++)
cin >> map[i][j];
for( i =1; i<= N ; i++)
for( j = 1; j<=N ; j++) {
if(map[i][j] > 0 && visited[i][j] == 0) {
visited[i][j] = 1;
map[i][j] = seq;
q.push({i,j});
CurveNum();
seq++;
}
}
memset(visited , 0 , sizeof(visited) );
for( i =1; i<=N ; i++)
for( j =1; j<=N ; j++) {
if(map[i][j] > 0) {
q.push({i,j});
BFS( map[i][j] );
memset(visited , 0 ,sizeof(visited));
}
}
cout << Min;
return 0;
}
|
'백준 (BOJ) > BFS' 카테고리의 다른 글
백준)13460 : 구슬탈출 2 (0) | 2019.05.11 |
---|---|
백준)2644-촌수 계산 (0) | 2019.05.11 |
백준)2468-안전 영역 (2) | 2019.04.30 |
백준)2583 - 영역 구하기 (0) | 2019.04.30 |
백준)14502-연구소 (0) | 2019.04.27 |
- Total
- Today
- Yesterday
- 그리디알고리즘
- greedy
- 플로이드
- A
- 사이클
- 백트레킹
- 라오킹전사
- 라이즈오브킹덤즈
- 이분매칭
- #스페인어 #스페인어인강 #스페인어공부 #시원스쿨스페인어
- KVK4
- stri
- 정렬
- 그리디
- 사이크
- dfs
- 백트래킹
- BFS
- 그래프
- HTML
- JavaSwing
- 다익스트라
- CSS
- 이분 매칭
- php
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |