백준 16234 - 인구 이동
Updated:
Java
16234 번 - 인구 이동
문제
N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접한 나라 사이에는 국경선이 존재한다. 모든 나라는 1×1 크기이기 때문에, 모든 국경선은 정사각형 형태이다.
인구 이동은 다음과 같이 진행되고, 더 이상 아래 방법에 의해 인구 이동이 없을 때까지 지속된다.
- 국경선을 공유하는 두 나라의 인구 차이가 L명 이상, R명 이하라면, 두 나라가 공유하는 국경선을 오늘 하루동안 연다.
- 위의 조건에 의해 열어야하는 국경선이 모두 열렸다면, 인구 이동을 시작한다.
- 국경선이 열려있어 인접한 칸만을 이용해 이동할 수 있으면, 그 나라를 오늘 하루 동안은 연합이라고 한다.
- 연합을 이루고 있는 각 칸의 인구수는 (연합의 인구수) / (연합을 이루고 있는 칸의 개수)가 된다. 편의상 소수점은 버린다.
- 연합을 해체하고, 모든 국경선을 닫는다.
각 나라의 인구수가 주어졌을 때, 인구 이동이 몇 번 발생하는지 구하는 프로그램을 작성하시오.
접근 방법
- (0,0) ~ (n-1, n-1) 까지 하나씩 탐색
- bfs를 이용하여 근처에 갈 수 있는 모든 곳 방문
- 방문 할 때마다 cnt 증가, 총합 증가, 방문했다는 증거 남긴다
- 방문 했던 곳의 인구를 균등하게 분배
- 1번 ~ 4번 과정을 while문으로 돌린다 -> 인구 이동이 발생하는 횟수 증가
코드
import java.util.*;
import java.io.*;
public class Main {
static int n, L, R, result;
static int[][] A;
static boolean[][] vis;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stk = new StringTokenizer(br.readLine());
n = stoi(stk.nextToken());
L = stoi(stk.nextToken());
R = stoi(stk.nextToken());
A = new int[n][n];
for(int i = 0; i < n; i++) {
stk = new StringTokenizer(br.readLine());
for(int j = 0; j < n; j++) {
A[i][j] = stoi(stk.nextToken());
}
}
boolean isMoved = false;
do {
vis = new boolean[n][n];
isMoved = false;
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
if(!vis[i][j]) {
if(!isMoved)
isMoved = BFS(i,j);
else {
BFS(i,j);
}
}
}
}
if(isMoved) {
result++;
}
}while(isMoved);
System.out.println(result);
br.close();
}
// 우 하 좌 상
static int[] dy = {0, -1, 0, 1};
static int[] dx = {1, 0, -1, 0};
private static boolean BFS(int y, int x) {
boolean ismoved = false;
Queue<Pair> q = new LinkedList<>();
Queue<Pair> saved = new LinkedList<>();
q.add(new Pair(y,x));
int sum = 0, cnt = 0, ny, nx;
Pair p;
while(!q.isEmpty()) {
p = q.poll();
saved.add(p);
for(int i = 0; i < 4; i++) {
ny = p.y + dy[i];
nx = p.x + dx[i];
if(isIn(ny,nx,n) && !vis[ny][nx] && CanMove(A[p.y][p.x], A[ny][nx])) {
q.add(new Pair(ny,nx));
ismoved = true;
sum += A[ny][nx];
vis[ny][nx] = true;
cnt++;
}
}
}
if(ismoved) { // 한 번이라도 연합 되면
int rst = sum / cnt;
while(!saved.isEmpty()) {
p = saved.poll();
A[p.y][p.x] = rst;
}
}
else { // 연합이 되지 않으면
vis[y][x] = false;
}
return ismoved;
}
public static class Pair{
int y;
int x;
Pair(int k,int v){
y = k;
x = v;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("[").append(y).append(", ").append(x).append("]");
return builder.toString();
}
}
// 주어진 범위 안에 있는가
public static boolean isIn(int y, int x, int size){
if(y < 0 || y == size || x < 0 || x == size)
return false;
return true;
}
public static boolean CanMove(int A, int B) {
int diff = Math.abs(A - B);
if(L <= diff && diff <= R) {
return true;
}
return false;
}
static int stoi(String str) {
return Integer.parseInt(str);
}
}
총평
난이도
⭐⭐⭐★★
후기
if(isIn(ny,nx,n) && !vis[ny][nx] && CanMove(A[p.y][p.x], A[ny][nx])) {
q.add(new Pair(ny,nx));
ismoved = true;
sum += A[ny][nx];
vis[ny][nx] = true;
cnt++;
}
BFS는 새로이 갈 수 있는 나라가 만나면,
방문한 인구수의 합, 나라의 수, 방문여부를 if()안에 넣어야한다.
이를 바깥에 넣어서 고생했다.
개선할 점
없