Coding Test/Baekjoon
백준 16234번 인구 이동 (JAVA)
good_da22
2022. 10. 2. 15:53
백준 16234번 인구 이동 (JAVA)
난이도
- 골드 5
알고리즘 분류
- 구현
- 그래프 이론
- 그래프 탐색
- 너비 우선 탐색
- 시뮬레이션
풀이
너비 우선 탐색을 통해 전체 데이터내에서 연합의 여부를 확인
연합이 발생하는 경우, 다음 단계로 이동
연합이 발생하지 않는 경우, 종료
각 단계 내에서 너비 우선 탐색을 진행, 각 연합 내에서 새로운 인구 수 계산
단계가 끝나고 방문여부 초기화
코드
import java.io.*;
import java.util.*;
public class Main {
static int N, L, R;
static int[][] map;
static int[] dx = { -1, 0, 1, 0 }; // 상, 우, 하, 좌
static int[] dy = { 0, 1, 0, -1 };
static boolean[][] visited;
static int answer;
public static void main(String[] args) throws Exception {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
StringBuilder sb = new StringBuilder();
StringTokenizer st = new StringTokenizer(in.readLine());
N = Integer.parseInt(st.nextToken());
L = Integer.parseInt(st.nextToken());
R = Integer.parseInt(st.nextToken());
map = new int[N][N];
visited = new boolean[N][N];
answer = 0;
for (int i = 0; i < N; i++) {
st = new StringTokenizer(in.readLine());
for (int j = 0; j < N; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
// 전체 상태 확인
// L명 이상, R명 이하면 연합으로 연결
// 연결된 연합은 (연합 인구수) / 칸의 개수
// 한 번 확인이 끝나면 인구 이동 발생 +1
// 더 이상 이동이 없으면 종료
boolean checking = true;
while (checking) {
checking = false;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (!visited[i][j]) { // 아직 확인하지 않는 국가인 경우
boolean temp = bfs(i, j); // 인구이동 발생 여부 확인
if (temp) { // 한 번이라도 인구 이동이 발생했다면 다음 단계에서 인구 이동이 발생하는지 확인한다.
checking = true;
}
}
}
}
if (checking) { // 인구 이동이 한 번도 발생하지 않는 경우, 더 이상 인구 이동이 불가능하다.
answer++;
visited = new boolean[N][N]; // 새로운 인구이동을 확인하기 위해 방문 여부 초기화
}
}
sb.append(answer);
out.write(sb.toString());
out.close();
}
private static boolean bfs(int row, int col) {
List<Country> list = new ArrayList<>(); // 연합으로 묶이는 국가를 담기 위한 리스트
Queue<Country> queue = new ArrayDeque<>(); // 연합으로 묶이는 국가의 여부를 확인, 너비 우선 탐색
Country country = new Country(row, col, map[row][col]);
list.add(country); // 시작 국가 추가
queue.offer(country); // 시작 국가 추가
int cnt = 1;
int sum = map[row][col];
visited[row][col] = true;
while (!queue.isEmpty()) {
Country current = queue.poll();
int curRow = current.row;
int curCol = current.col;
int curSize = current.size;
for (int idx = 0; idx < 4; idx++) { // 4방향 탐색, 인접한 국가 탐색
int nextRow = curRow + dx[idx];
int nextCol = curCol + dy[idx];
if (check(nextRow, nextCol) && !visited[nextRow][nextCol]) { // map의 영역을 벗어나지 않고 아직 탐색하지 않는 국가인 경우
int diffSize = Math.abs(map[nextRow][nextCol] - curSize); // 현재 국가와 인구 수 차이 계산
if (L <= diffSize && diffSize <= R) { // 인구 수 차이가 주어진 범위 내에 있을 때
Country nextCountry = new Country(nextRow, nextCol, map[nextRow][nextCol]);
list.add(nextCountry); // 연합에 추가
queue.offer(nextCountry); // 다음 탐색을 위해 큐에 추가
sum += map[nextRow][nextCol]; // 연합의 전체 인구 수 증가
cnt++; // 연합의 국가 수 증가
visited[nextRow][nextCol] = true; // 탐색 여부 확인(연합 결성 여부)
// 연합에 포함되지 않는 경우 다른 연합에 포함될 수 있기 때문에 현재 연합에 포함 여부를 확인한다.
}
}
}
}
if (cnt > 1) { // 연합이 결성된 경우(연합의 국가 수 가 2이상인 경우)
int newSize = sum / cnt; // 연합내 국가들의 새로운 인구 수
for (int i = 0; i < list.size(); i++) { // 연합으로 국가들
Country c = list.get(i);
map[c.row][c.col] = newSize; // 새로운 인구수 정의
}
return true; // 인구 이동 발생 여부
}
return false;
}
private static boolean check(int nextRow, int nextCol) {
return (0 <= nextRow && nextRow < N) && (0 <= nextCol && nextCol < N);
}
}
class Country {
int row;
int col;
int size;
public Country(int row, int col, int size) {
this.row = row;
this.col = col;
this.size = size;
}
}