[백준] 16234 인구이동
간단하게 BFS로 풀어보았다.
국경선 오픈 조건(l, r) 이 성립하면 큐에 추가하는 방식이다.
다만 큐에 추가된 적이 있는 곳의 좌표를 따로 기록해놔야 나중에 인구를 재배치 할 수 있으므로 어딘가에 기록해두도록 하자.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
import java.util.StringTokenizer;
class Pair{
int x;
int y;
Pair(int x, int y){
this.x = x;
this.y = y;
}
}
public class Main {
static int[][] map;
static int n;
static int l;
static int r;
static int[] dx = {1, -1, 0, 0};
static int[] dy = {0, 0, 1, -1};
static boolean[][] check;
static void bfs(int i, int j) {
Queue<Pair> q = new LinkedList<>();
check[i][j] = true;
q.add(new Pair(i, j));
// 연합이 될 국가의 좌표를 기억할 스택(꼭 스택이 아니어도 좋다)
Stack<Pair> st = new Stack<Pair>();
st.add(new Pair(i, j));
// 연합의 총 인구수를 저장할 변수
int sum = map[i][j];
while(!q.isEmpty()) {
Pair p = q.remove();
int x = p.x;
int y = p.y;
// 네 방향에 대해 조사한다
for(int k = 0 ; k < 4 ; k++) {
int nx = x + dx[k];
int ny = y + dy[k];
// 다음 좌표는 맵 내에 존재해야 하며 방문한적이 없어야 한다.
if(nx >= 0 && nx < n && ny >= 0 && ny < n && check[nx][ny] == false) {
// 두 국가 간 인구 수의 차이
int diff = Math.abs(map[nx][ny]-map[x][y]);
// 차이가 l이상 r이하면 연합을 맺을 수 있다
if(diff >= l && diff <= r) {
check[nx][ny] = true;
q.add(new Pair(nx, ny)); // 큐에 추가
st.add(new Pair(nx, ny)); // 연합 저장
sum += map[nx][ny]; // 인구 수 더해주기
}
}
}
}
if(st.size() == 1) return; // 연합이 단 한군데도 없다면 그냥 종료하자
int size = st.size(); // 연합의 크기
int move = sum/size; // 새로 배치될 국가 당 인구 수
while(!st.isEmpty()) {
Pair p = st.pop();
map[p.x][p.y] = move; // 새로 인구를 넣어준다
}
}
// 더이상 인구 이동이 가능할지 여부를 반환하는 함수
static boolean hasMoreMove() {
// 우측의 국가와 연합이 가능할까?
for(int i = 0 ; i < n ; i++) {
for(int j = 0 ; j < n-1 ; j++) {
int diff = Math.abs(map[i][j] - map[i][j+1]);
if(diff >= l && diff <= r) {
return true; // 가능하면 트루 반환
}
}
}
// 아래의 국가와 연합이 가능할까?
for(int i = 0 ; i < n-1 ; i++) {
for(int j = 0 ; j < n ; j++) {
int diff = Math.abs(map[i][j] - map[i+1][j]);
if(diff >= l && diff <= r) {
return true; // 가능하면 트루 반환
}
}
}
// 이 모든 반복문에서 한번도 안걸렸다면 더이상 인구 이동이 불가능한 상태
return false;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
l = Integer.parseInt(st.nextToken());
r = Integer.parseInt(st.nextToken());
map = new int[n][n];
for(int i = 0 ; i < n ; i++) {
st = new StringTokenizer(br.readLine());
for(int j = 0 ; j < n ; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
int cnt = 0;
while(true) { // 계속 반복한다
// 더이상의 인구이동이 가능하다면 말이다
if(!hasMoreMove()) break;
// 방문 여부 초기화
check = new boolean[n][n];
for(int i = 0 ; i < n ; i++) {
for(int j = 0 ; j < n ; j++) {
if(check[i][j] == false) {
// 방문한 적 없는 국가에 대하여 BFS 해주자
bfs(i, j);
}
}
}
// 인구 이동이 끝났다. 카운트를 올리자!
cnt++;
}
System.out.println(cnt); // 최종 카운트 반환
}
}
Comments