본문 바로가기

Algorithms/Baekjoon OJ

[Baekjoon]2146.다리만들기

2146.다리만들기 

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

 

2146번: 다리 만들기

여러 섬으로 이루어진 나라가 있다. 이 나라의 대통령은, 섬들을 잇는 다리를 만들겠다는 공약으로 인기몰이를 해 당선될 수 있었다. 하지만 막상 대통령에 취임하자, 다리를 놓는다는 것이 아깝다는 생각을 하게 되었다. 그래서 그는, 생색내는 식으로 한 섬과 다른 섬을 잇는 다리 하나만을 만들기로 하였고, 그 또한 다리를 가장 짧게 하여 돈을 아끼려 하였다. 이 나라는 N×N크기의 이차원 평면상에 존재한다. 이 나라는 여러 섬으로 이루어져 있으며, 섬이란 동서

www.acmicpc.net


dfs와 bfs를 모두 사용하여 풀 수 있는 문제였다. 크게 두 부분으로 나누어서 풀었다.

 

  1. 섬을 구분짓는다.(dfs)
  2. 서로 다른 섬을 잇는 다리의 최솟값을 구한다.(bfs)

먼저 섬을 구분짓기 위해서 육지인 부분을 -1로 모두 바꾼다. (섬 라벨링을 1부터 하기 위해서)

dfs를 수행하면서 -1인 부분을 라벨링할 인덱스 idx값으로 바꿔주고 dfs가 끝나면 idx++ 을 해서 다음 섬의 라벨링을 하도록 한다. 이 부분은 기존에 풀었던 dfs 문제들과 거의 같아서 어렵지 않게 풀었다. 

 

다음은 섬의 각 지점에서 bfs를 수행하여 다른 섬으로 가는 최단거리를 구한다. dist배열에 거리를 저장하면서 최솟값을 갱신한다. bfs를 시작한 지점의 섬 라벨과 도착한 지점의 섬 라벨이 다르고 바다가 아니면 탐색을 멈추고 최솟값을 갱신한다. 

 

처음에는 bfs가 끝나면  dist, visited, min값을 초기화해줬더니 답이 계속 0이 나왔다. 그래서 bfs를 하기 전에 초기화를 해줬더니 답이 제대로 나왔다. 이거 고치는데만 1시간 넘게 쓴거 같다.. 

 

다른 사람들의 풀이에 비해 메모리를 많이쓰고 시간도 훨씬 많이 걸리긴 하지만 직관적으로 이해하기는 내 풀이가 쉬웠다.(내가 생각한 풀이라서 그럴수도..) 

 

private static void explore() { // 섬 라벨링. 
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				if (map[i][j] == -1 && !visited[i][j]) {
					map[i][j] = idx;
					visited[i][j] = true;
					dfs(j, i);
					idx++;
				}
			}
		}
	}
    
private static void dfs(int x, int y) {
		for (int i = 0; i < 4; i++) {
			int nextX = x + dx[i];
			int nextY = y + dy[i];
			if (nextX < 0 || nextY < 0 || nextX >= N || nextY >= N) {
				continue;
			}
			if (visited[nextY][nextX] || map[nextY][nextX] == 0) {
				continue;
			}
			map[nextY][nextX] = idx;
			visited[nextY][nextX] = true;
			dfs(nextX, nextY);
		}
	}

dfs를 통해 섬을 라벨링.

 

private static void buildBrg() {  // 다리 놓기. 
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				min = Integer.MAX_VALUE;
				for (boolean[] row : visited) {
					Arrays.fill(row, false);
				}
				for (int[] row : dist) {
					Arrays.fill(row, 0);
				}
				if (map[i][j] != 0 && !visited[i][j]) {
					visited[i][j] = true;
					bfs(j, i);
					ans = Math.min(ans, min);
				}
			}
		}
	}
private static void bfs(int x, int y) {
		Queue q = new LinkedList<>();
		q.add(new Point(x, y));

		while (!q.isEmpty()) {
			Point p = q.poll();
			int curX = p.x;
			int curY = p.y;
			for (int i = 0; i < 4; i++) {
				int nextX = curX + dx[i];
				int nextY = curY + dy[i];
				if (nextX < 0 || nextY < 0 || nextX >= N || nextY >= N) {
					continue;
				}
				if (visited[nextY][nextX] || map[nextY][nextX] == map[y][x]) {	
					continue;
				}
				if (map[y][x] != map[nextY][nextX] && map[nextY][nextX] != 0) {
					min = Math.min(min, dist[curY][curX]);
					break;
				}
				visited[nextY][nextX] = true;
				dist[nextY][nextX] = dist[curY][curX] + 1;
				q.add(new Point(nextX, nextY));
			}
		}
	}

bfs로 다리길이의 최솟값 갱신.

 

<전체코드>

'Algorithms > Baekjoon OJ' 카테고리의 다른 글

[Baekjoon]2206.벽 부수고 이동하기  (0) 2019.07.09
[Baekjoon]5427.불  (0) 2019.07.05
[Baekjoon]2589.보물섬  (0) 2019.06.26
[Baekjoon]2573.빙산  (0) 2019.06.25
[Baekjoon]2468.안전 영역  (0) 2019.06.24