2146 다리 만들기
https://www.acmicpc.net/problem/2146
문제설명
그래프를 탐색하여 섬들 간의 최단 다리 길이를 찾는다.
접근방식
O(N^4) 시간복잡도
- DFS 탐색: 섬을 번호 매기기 위해 O(N^2) 시간이 걸린다.
- BFS 탐색: 각 섬에서 다른 섬까지의 최단 거리를 찾기 위해 O(N^4) 시간이 걸린다.
(각 셀에 대해 BFS를 수행할 수 있기 때문)
즉, 지도 크기 N이 커질수록 처리 시간이 급격히 증가한다.
문제 조건 분석 과정
- 모든 섬을 탐색하여 고유 번호를 매기고 (DFS 사용)
- 각 섬에서 다른 섬까지의 최단 거리를 계산 (BFS 사용)
- 섬이 여러 개 있을 수 있으며, 모든 섬에 대해 다리 길이를 계산해야 함
전체코드
import java.util.*;
import java.io.*;
public class Main {
static int N; // 지도 크기
static int res = 10001; // 결과를 큰 값으로 초기화
static int[][] req = new int[101][101]; // 섬 번호를 저장할 지도
static boolean[][] isIslandCheck = new boolean[101][101]; // 방문 여부를 확인할 지도
static int[] dx = {1, 0, -1, 0}; // x 방향으로 이동할 때의 변화 (오른쪽, 아래, 왼쪽, 위)
static int[] dy = {0, 1, 0, -1}; // y 방향으로 이동할 때의 변화 (오른쪽, 아래, 왼쪽, 위)
// DFS를 이용해 섬을 탐색하고 번호를 매긴다
static void dfs(int y, int x, int islandNum) {
isIslandCheck[y][x] = true; // 현재 셀을 방문 처리
req[y][x] = islandNum; // 현재 셀에 섬 번호를 부여
// 4 방향으로 이동
for (int i = 0; i < 4; i++) {
int ny = y + dy[i]; // 새로운 y 좌표
int nx = x + dx[i]; // 새로운 x 좌표
// 경계 확인
if (ny < 0 || ny >= N || nx < 0 || nx >= N) continue;
// 동일 섬의 미방문 셀인 경우 DFS 계속 수행
if (req[ny][nx] != 0 && !isIslandCheck[ny][nx]) dfs(ny, nx, islandNum);
}
}
// BFS를 이용해 섬을 확장하며 가장 짧은 다리 길이를 찾는다
static void enlargeIsland(int[][] map, int islandNum) {
boolean[][] check = new boolean[101][101]; // BFS 중 방문 여부를 확인할 지도
Queue<Island> queue = new LinkedList<>(); // BFS를 위한 큐
// 현재 섬의 모든 셀을 큐에 추가
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (map[i][j] == islandNum) {
queue.add(new Island(i, j, 0)); // 시작 셀과 거리 0을 큐에 추가
check[i][j] = true;
}
}
}
// BFS 수행
while (!queue.isEmpty()) {
Island position = queue.poll(); // 현재 위치와 거리 얻기
// 4 방향으로 이동
for (int i = 0; i < 4; i++) {
int ny = position.y + dy[i]; // 새로운 y 좌표
int nx = position.x + dx[i]; // 새로운 x 좌표
// 경계 확인
if (ny < 0 || ny >= N || nx < 0 || nx >= N) continue;
// 다른 섬을 발견하면, 현재까지의 거리로 결과 업데이트
if (map[ny][nx] != islandNum && req[ny][nx] != 0) {
if (res > position.cnt && position.cnt != 0) res = position.cnt;
} else {
// 물인 경우와 방문하지 않은 경우
if (map[ny][nx] == 0 && !check[ny][nx]) {
check[ny][nx] = true;
queue.add(new Island(ny, nx, position.cnt + 1)); // 거리 증가시켜 큐에 추가
}
}
}
}
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine()); // 지도 크기 입력
// 지도 입력
for (int i = 0; i < N; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
for (int j = 0; j < N; j++) {
req[i][j] = Integer.parseInt(st.nextToken());
}
}
int islandNum = 1; // 섬 번호 초기화
// 모든 섬에 번호를 매기기
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (!isIslandCheck[i][j] && req[i][j] != 0) {
dfs(i, j, islandNum);
islandNum++;
}
}
}
// 모든 섬에 대해 가장 짧은 다리 찾기
for (int i = 1; i < islandNum; i++) {
int[][] map = req.clone(); // 지도 복사
enlargeIsland(map, i);
}
System.out.println(res);
}
}
// 위치와 거리를 나타내는 클래스
class Island {
int y;
int x;
int cnt;
Island(int y, int x, int cnt) {
this.y = y;
this.x = x;
this.cnt = cnt;
}
}
'자료구조 > 문제풀이' 카테고리의 다른 글
알고리즘 스터디 3주차 문제 정리 (0) | 2024.08.24 |
---|---|
[백준 JAVA] 7562 나이트의 이동 (0) | 2024.08.24 |
[백준 JAVA] 16954 움직이는 미로 탈출 (0) | 2024.08.23 |
[백준 JAVA] 1743 음식물 피하기 (0) | 2024.08.23 |
[백준 JAVA] 1991 트리 순회 (0) | 2024.08.23 |