하루에 한 문제

[BOJ-16234] 인구이동 -Java 본문

알고리즘/백준

[BOJ-16234] 인구이동 -Java

dkwjdi 2021. 2. 14. 22:27

https://www.acmicpc.net/problem/16234

 

16234번: 인구 이동

N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접한 나라 사이에는 국경선이 존재한다. 모

www.acmicpc.net

package 시뮬레이션_review;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.StringTokenizer;

public class boj_16234_인구이동 {
	static int N,L,R,result,map[][];
	static int dx[]= {0,0,-1,1};
	static int dy[]= {-1,1,0,0};
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		result=0;
		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());
			}
		}
		solve();
		System.out.println(result);
		
	}
	private static void solve() {
		while(true) {
			int sectionNo=1;
			int [][] section = new int [N][N];
			List <int[]> totalInfo = new ArrayList<>(); // 몇번연합, 연합을 이루는 칸갯수, 연합 인구수
			
			for(int i=0; i<N; i++) {
				for(int j=0; j<N; j++) {
					if(section[i][j]!=0) continue; //이미 간곳이라면 
					if(bfs(section,totalInfo,sectionNo,i,j)) sectionNo++; //연합이 만들어지면 숫자++
				}
			}
			if(sectionNo==1) break; //연합이 더이상 없으면
			divPopoulation(totalInfo,section);
			result++;
		}
		
	}
	private static void divPopoulation(List<int[]> totalInfo, int[][] section) {
		int population[]=new int[totalInfo.size()];
		for(int i=0; i<totalInfo.size(); i++) {
			int []Info=totalInfo.get(i);
			population[i]=Info[2]/Info[1];
		}
		
		for(int i=0; i<N; i++) {
			for(int j=0; j<N; j++) {
				if(section[i][j]==-1 || section[i][j]==0) continue;
				else map[i][j]=population[section[i][j]-1];
			}
		}
		
	}
	private static boolean bfs(int[][] section, List<int[]> totalInfo, int sectionNo, int x, int y) {
		section[x][y]=-1;//우선 방문처리
		int totalPopulation=map[x][y];
		int sectionCnt=1;
		Queue <int[]> queue = new LinkedList<>();
		
		queue.offer(new int[] {x,y});
		
		while(!queue.isEmpty()) {
			int []point=queue.poll();
			
			for(int d=0; d<4; d++) {
				int nx=point[0]+dx[d];
				int ny=point[1]+dy[d];
				
				if(nx<0 || ny<0 || nx>=N || ny>=N || section[nx][ny]!=0) continue;
				if(!isBound(point[0],point[1],nx,ny)) continue; //L,R확인
				section[nx][ny]=sectionNo;
				sectionCnt++;
				totalPopulation+=map[nx][ny];
				queue.offer(new int[] {nx,ny});
			}
		}
		
		if(map[x][y]==totalPopulation) return false; //연합 형성이 안됬으면 
		else {
			totalInfo.add(new int[] {sectionNo, sectionCnt, totalPopulation});
			section[x][y]=sectionNo;// 연합에 넣고
			return true; //true
		}
	}
	private static boolean isBound(int x, int y, int nx, int ny) {
		int check=Math.abs(map[x][y]-map[nx][ny]);
		if(L<=check && R>=check) return true;
		return false;
	}
}

 

소요시간 : 55분

 

프로젝트 때문에 알고리즘을 너무 오랜만에 풀었습니다...

오랜만에 푸니까 뭔가 잘 안 풀리네요. 내일부터는 다시 하루에 한 문제 시작합니다!

 

로직을 살펴보면

 

1. BFS를 통해 연합을 만들어 줍니다.

2. 연합을 만들면서 각 연합이 몇 개의 칸으로 이루어졌는지, 총인구수가 몇인지 저장해줍니다.

3. 만약 연합이 있다면 위에서 구한 내용을 토대로 map을 바꿔줍니다.

 

주의사항 - 모든 연합을 구하고 나서 map을 바꿔야 합니다.

              연합을 구하는 도중에 map을 바꾸면 원래 연합이어야 하는데 연합이 안되거나,

              연합이 아닌데 연합이 되는 경우가 생깁니다.

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

[BOJ-1197] 최소 스패닝 트리 -Java  (0) 2021.03.19
[BOJ-16236] 아기 상어 -Java  (0) 2021.03.04
[BOJ-14888]연산자 끼워넣기 -Java  (2) 2021.02.07
[BOJ-14503] 로봇 청소기 -Java  (2) 2021.01.31
[BOJ-14502] 연구소 -Java  (0) 2021.01.30
Comments