문제 - https://www.acmicpc.net/problem/16234
16234번: 인구 이동
N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접한 나라 사이에는 국경선이 존재한다. 모
www.acmicpc.net
import java.io.*;
import java.util.*;
public class Main {
static int N, L, R, Day = 0;
static int[] dr = {-1, 0, 1, 0};
static int[] dc = {0, 1, 0, -1};
static int[][] A;
static class Nation{
int r, c;
public Nation(int r, int c){
this.r = r;
this.c = c;
}
}
static class United{
int all;
ArrayList<Nation> nations;
public United(){
this.all = 0;
this.nations = new ArrayList<>();
}
}static ArrayList<United> unites;
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
L = Integer.parseInt(st.nextToken());
R = Integer.parseInt(st.nextToken());
A = new int[N][N];
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < N; j++) {
A[i][j] = Integer.parseInt(st.nextToken());
}
}
while(true){
lookup();
if (unites.size()==0)
break;
move();
Day++;
}
bw.write(Day+"\n");
bw.flush();
bw.close();
br.close();
}
static void lookup(){
boolean[][] visit = new boolean[N][N];
unites = new ArrayList<>();
for (int i = 0; i < N; i++) { // 0행 부터 N-1행까지
for (int j = 0; j < N; j++) {
Nation from = new Nation(i, j);
for (int w = 1; w < 3; w++) { // 오른쪽하고 아랫쪽만 확인
Nation to = new Nation(i + dr[w], j + dc[w]);
if(can_move(from, to) && !visit[to.r][to.c]){ // 갈 수 있고, 간적없으면,
United tmp = new United(); // 새로운 연합 만들고,
Queue<Nation> Q = new LinkedList();
Q.add(from);
visit[from.r][from.c] = true;
while (!Q.isEmpty()){ // BFS
Nation cur = Q.poll();
tmp.nations.add(cur); // 연합에 추가
tmp.all += A[cur.r][cur.c]; // 연합인구 추가
for (int k = 0; k < 4; k++) {
Nation next = new Nation(cur.r + dr[k], cur.c + dc[k]);
if(can_move(cur, next) && !visit[next.r][next.c]) {// 갈 수 있고, 간적없으면,
Q.add(next);
visit[next.r][next.c] = true; // 확인
}
}
}
unites.add(tmp);
}
}
}
}
}
static boolean can_move(Nation from, Nation to){
if (0<=to.r && to.r<N && 0<= to.c && to.c<N // 범위안에 있고
&& L <= Math.abs(A[to.r][to.c] - A[from.r][from.c]) // 최솟값 만족하고
&& Math.abs(A[to.r][to.c] - A[from.r][from.c]) <= R) // 최댓값 만족하면
return true; // 이동가능
return false; // 이동못함
}
static void move(){
for (United united : unites){
int population = united.all / united.nations.size();
for (Nation nation : united.nations){
A[nation.r][nation.c] = population;
}
}
}
}
상어중학교 문제와 굉장히 비슷한 문제다.
BFS만 논리적으로 문제없이 구현한다면, 크게 무리없이 해결할 수 있는 문제로 보인다.
'공부 > algorithm' 카테고리의 다른 글
BOJ 고스택(3425) - Java (0) | 2021.09.13 |
---|---|
BOJ 사다리 조작(15684) - Java (0) | 2021.09.07 |
BOJ 상어 중학교(21609) - Java (0) | 2021.09.02 |
BOJ 경사로(14890) - Java (0) | 2021.09.02 |
BOJ 상어 초등학교(21608) - Java (0) | 2021.08.31 |