본문 바로가기
알고리즘/BFS

[백준][JAVA] 3197번 백조의 호수

by 박뀨뀨 2023. 12. 22.
 

3197번: 백조의 호수

입력의 첫째 줄에는 R과 C가 주어진다. 단, 1 ≤ R, C ≤ 1500. 다음 R개의 줄에는 각각 길이 C의 문자열이 하나씩 주어진다. '.'은 물 공간, 'X'는 빙판 공간, 'L'은 백조가 있는 공간으로 나타낸다.

www.acmicpc.net

코드

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {

	static int R, C, parents[], swan[][] = new int[2][2];
	static char lake[][];
	static int dr[] = {-1, 0, 1, 0}; // 상, 우, 하, 좌
	static int dc[] = {0, 1, 0, -1}; // 상, 우, 하, 좌
	
	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		StringTokenizer st = new StringTokenizer(br.readLine()); // 입력의 첫째 줄
		
		R = Integer.parseInt(st.nextToken()); // 호수의 행 갯수
		C = Integer.parseInt(st.nextToken()); // 호수의 열 갯수
		
		parents = new int[R * C]; // disjoint set에 사용할 집합의 루트번호 저장할 배열
		lake = new char[R][C]; // 호수의 정보
		
		int cnt = 0, idx = 0;
		for (int i = 0; i < R; i++) {
			char[] temp = br.readLine().toCharArray();
			for (int j = 0; j < C; j++) {
				lake[i][j] = temp[j];
				parents[cnt] = cnt++;
				
				// 두마리 백조의 위치정보 저장
				if (lake[i][j] == 'L') {
					swan[idx][0] = i;
					swan[idx][1] = j;
					idx++;
				}
			}
		}
		
		boolean[][] visited = new boolean[R][C]; // BFS 방문체크배열
		
		Queue<int[]> qWater = new ArrayDeque<>(); // 물
		Queue<int[]> qIce = new ArrayDeque<>(); // 빙판
		
		// 물 공간 disjoint set 생성(유니온 파인드)
		for (int i = 0; i < R; i++) {
			for (int j = 0; j < C; j++) {
				if (visited[i][j] || lake[i][j] == 'X') continue; // 이미 방문한 곳이거나, 빙판이 있는 곳인 경우 skip
				
				visited[i][j] = true;
				int root = convert(i, j); // disjoint Set의 루트노드번호
				qWater.offer(new int[] {i, j});
				
				while (!qWater.isEmpty()) {
					int[] info = qWater.poll();
					int r = info[0], c = info[1]; // 현정점의 좌표
					
					for (int d = 0; d < 4; d++) { // 현정점 기준 상하좌우 4방향 탐색
						int nr = r + dr[d];
						int nc = c + dc[d];
						
						// 호수의 범위를 벗어났거나, 이미 방문한 정점인 경우 skip
						if (nr < 0 || nr >= R || nc < 0 || nc >= C || visited[nr][nc]) {
							continue;
						}
						
						visited[nr][nc] = true;
						if (lake[nr][nc] == 'X') {
							qIce.offer(new int[] {nr, nc, 1});
						} else {
							qWater.offer(new int[] {nr, nc});
							union(root, convert(nr, nc));
						}
					}
				}
			}
		}
		
		if (isUnion(convert(swan[0][0], swan[0][1]), convert(swan[1][0], swan[1][1]))) {
			System.out.println(0);
			return;
		}
		
		while (!qIce.isEmpty()) {
			int[] info = qIce.poll();
			int r = info[0], c = info[1], time = info[2];
			lake[r][c] = '.'; // 빙판이 있던 곳을 물로 변환
			
			for (int d = 0; d < 4; d++) { // 4방탐색
				int nr = r + dr[d];
				int nc = c + dc[d];
				
				// 호수 밖을 벗어났거나, 빙판인 경우 skip
				if (nr < 0 || nr >= R || nc < 0 || nc >= C || lake[nr][nc] == 'X') {
					continue;
				}
				
				union(convert(nr, nc), convert(r, c)); // Union Find
			}
			
			// 두 백조가 서로 만날 수 있는 경우
			if (isUnion(convert(swan[0][0], swan[0][1]), convert(swan[1][0], swan[1][1]))) {
				System.out.println(time); // 걸리는 날 출력
				break;
			}
			
			for (int d = 0; d < 4; d++) { // 4방 탐색(현정점 기준으로 인접 빙판을 큐에 삽입)
				int nr = r + dr[d];
				int nc = c + dc[d];
				
				// 호수 밖으로 벗어났거나, 빙판이 아니거나, 이미 방문한 지점인 경우 skip
				if (nr < 0 || nr >= R || nc < 0 || nc >= C || lake[nr][nc] != 'X' || visited[nr][nc]) {
					continue;
				}
				
				visited[nr][nc] = true; // 방문 체크
				qIce.offer(new int[] {nr, nc, time + 1}); // 빙판정보 저장하는 큐에 정보 삽입
			}
		}
		
	}
	
	static int find(int x) {
		if (parents[x] == x) return parents[x];
		return parents[x] = find(parents[x]);
	}
	
	static void union(int a, int b) {
		int rootA = find(a);
		int rootB = find(b);
		
		if (rootA == rootB) return;
		
		parents[rootB] = rootA;
	}
	
	static boolean isUnion(int a, int b) {
		return find(a) == find(b);
	}
	
	// 2차원 좌표 정보 -> 1차원 값으로 변환
	static int convert(int r, int c) {
		return r * C + c;
	}

}

설명

두 백조가 서로 만날 수 있는지 여부 => Disjoint Set 사용
물과 접촉해있는 얼음이 차례대로 녹는다 => BFS 사용

얼음이 녹아 물이 된 곳을 Union Find를 통해 연결하고 두 백조가 서로 만날 수 있을 때 걸리는 날을 결과로 출력했다.

728x90

'알고리즘 > BFS' 카테고리의 다른 글

[백준][JAVA] 13913번 숨바꼭질 4  (1) 2024.02.21
[백준][JAVA] 1325번 효율적인 해킹  (2) 2024.02.01
[백준][JAVA] 16236번 아기 상어  (0) 2023.12.18