Uknow's Lab.
article thumbnail

https://www.acmicpc.net/problem/2146

 

2146번: 다리 만들기

여러 섬으로 이루어진 나라가 있다. 이 나라의 대통령은 섬을 잇는 다리를 만들겠다는 공약으로 인기몰이를 해 당선될 수 있었다. 하지만 막상 대통령에 취임하자, 다리를 놓는다는 것이 아깝다

www.acmicpc.net

 

난이도 : 골드 3
태그 : 그래프이론, 그래프탐색, 너비우선탐색

 

 

1. 설명

앞서 포스팅한 다리만들기 2와 비슷하지만, 1이기 때문에 2보단 쉽습니다.

여러개의 섬이 있을 때, 두 섬을 하나의 다리로 이으면 되기 때문입니다.

 

2. 접근방법

1) DFS / BFS로 모든 섬을 그룹화한다. 이 때, 모든 섬의 좌표를 저장해놓는다.

2) 1번 과정에서 저장해놓은 각 섬의 모든 좌표를 기준으로 BFS를 수행한다.

2-1) BFS 수행 중, 시작 지점과 같은 섬을 만났을 경우, 다음 케이스로 넘어간다. 같은 섬 끼리는 다리를 연결하지 않기 때문이다.

2-2) BFS 수행 중, 다른 섬을 만났을 경우 탐색을 종료한다. 첫 시작지점과 종료지점의 거리가 다리의 길이가 되며, 매 번 다리의 최솟값을 초기화한다.

3) 각 섬의 모든 좌표에서 BFS가 끝나면 다리의 최소 길이를 출력한다.

 

처음에는 연산량이 좀 많을 것 같아 괜찮나 싶었지만,

n의 최대 크기가 100밖에 되지 않아 충분히 시간 안에 통과가 가능할 것으로 판단했습니다.

 

 

 

3. 소스코드

<kotlin />
import java.util.LinkedList import java.util.Queue import java.util.StringTokenizer data class Node(val x: Int, val y: Int) val dx = arrayOf(0, 0, 1, -1) val dy = arrayOf(1, -1, 0, 0) fun main() = with(System.`in`.bufferedReader()) { val n = readLine().toInt() val map = Array(n) { val st = StringTokenizer(readLine()) Array(n) { st.nextToken().toInt() } } var visited = Array(n) { Array(n) { false } } // 섬의 모든 좌표를 저장해 놓을 큐 val islands = LinkedList<Node>() as Queue<Node> // 섬을 그룹화할때, 섬의 번호 var groupIndex = 2 // 모든 섬을 그룹화 (BFS) repeat(n) { x -> repeat(n) { y -> if (!visited[x][y] && map[x][y] == 1) { // BFS visited[x][y] = true map[x][y] = groupIndex islands.add(Node(x, y)) val q = LinkedList<Node>() as Queue<Node> q.offer(Node(x, y)) while (q.isNotEmpty()) { val target = q.poll() for (i in 0 until 4) { val nx = target.x + dx[i] val ny = target.y + dy[i] if (nx !in 0 until n || ny !in 0 until n || visited[nx][ny] || map[nx][ny] != 1) continue q.offer(Node(nx, ny)) visited[nx][ny] = true islands.add(Node(nx, ny)) map[nx][ny] = groupIndex } } groupIndex++ } } } var minLength = Int.MAX_VALUE while (islands.isNotEmpty()) { // 각 섬의 모든 좌표에서 BFS 수행 val startPoint = islands.poll() val q = LinkedList<Node>() as Queue<Node> val visited = Array(n) { Array(n) { -1 } } visited[startPoint.x][startPoint.y] = 0 q.offer(Node(startPoint.x, startPoint.y)) // while 문 라벨링 bfs@ while (q.isNotEmpty()) { val target = q.poll() for (i in 0 until 4) { val nx = target.x + dx[i] val ny = target.y + dy[i] if (nx !in 0 until n || ny !in 0 until n || map[nx][ny] == map[startPoint.x][startPoint.y] || visited[nx][ny] != -1) continue // 시작 섬과 같지 않으면서 바다가 아님 -> 새로운 섬을 만남 if (map[nx][ny] != 0) { minLength = minOf(minLength, visited[target.x][target.y]) break@bfs // 라벨링한 반복문을 탈출 } q.offer(Node(nx, ny)) visited[nx][ny] = visited[target.x][target.y] + 1 } } } println(minLength) }

 

 

코드 상에서 BFS가 총 두 번 나타납니다.

섬을 그룹화하는데 한 번, 섬의 모든 좌표에서 다른 섬 까지의 최단경로를 찾는데 한 번.

물론, 섬을 그룹화할 때는 DFS를 써도 무방합니다.

 

 

4. 후기

다리만들기 2를 먼저 풀고와서 그런지, 어렵지 않게 풀 수 있었던 것 같습니다.

역시 DFS / BFS는 언제 해도 재밌는 거 같아요.

profile

Uknow's Lab.

@유노 Uknow

인생은 Byte와 Double 사이 Char다. 아무말이나 해봤습니다.