알고리즘/DFS & BFS

[백준]JAVA - 16234번: 인구 이동

K.두부 2022. 11. 3. 20:32
반응형

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

 

16234번: 인구 이동

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

www.acmicpc.net

풀이

인접해있는 땅과의 인구수 차이가 L과 R 사이이면 국경선이 열리고 연합 내의 동일한 인구수를 가진다.

 

위 문제는 bfs, dfs 아무거나 사용해도 무관하기 때문에 본인이 원하는 걸 사용하면 된다.

필자는 bfs를 이용해서 문제를 풀었다.

while (true) {
    visited = new boolean[N][N]; // 방문 유부
    isMove = false; // 변경 유무
			
    for (int i=0; i<N; i++) {
        for (int j=0; j<N; j++) {
            if (!visited[i][j]) bfs(i, j);
        }
    }
			
    if (!isMove) break;
    ans++;
}

해당 문제는 더 이상 인접한 땅과의 인구수 차이가 L과 R 사이가 없을 때까지 돌려야 한다.

그렇기 때문에 무한 반복문 안에 인구수 변경 유무를 판단할 isMove 변수를 넣은 후에 더 이상 위 조건이 없을 때까지 bfs를 돌린다.

 

public static void bfs(int x, int y) {
    Queue<Position> q = new LinkedList<>();
    ArrayList<Position> arrList = new ArrayList<>(); // 인구수를 평균내기 위한 배열
		
    arrList.add(new Position(x, y)); // 시작 땅 추가
    q.add(new Position(x, y));
    visited[x][y] = true;
    int sum = map[x][y];
		
    while(!q.isEmpty()) {
        Position now = q.poll();
			
        for (int i=0; i<4; i++) {
            int nx = now.x + dx[i];
            int ny = now.y + dy[i];
				
            if (nx < 0 || nx > N-1 || ny < 0 || ny > N-1 || visited[nx][ny]) continue;
				
            int sumxy = Math.abs(map[nx][ny] - map[now.x][now.y]);
				
            // 조건에 해당하는 땅 (인구수 차이가 L과 R사이)
            if (L <= sumxy && sumxy <= R) {
                sum += map[nx][ny];
					
                arrList.add(new Position(nx, ny));
                q.add(new Position(nx, ny));
                visited[nx][ny] = true;
            }
        }
    }
		
    // 변경할 값이 존재할 경우
    if (arrList.size() > 1) {
        int num = sum / arrList.size();
        for (int i=0; i<arrList.size(); i++) {
            map[arrList.get(i).x][arrList.get(i).y] = num;
        }
			
        isMove = true;
    }
}

bfs는 아주 기본적인 구조에서 인구수를 변경해야 하는 조건에 들어맞는 땅을 넣을 arrList 배열을 추가했다.

조건에 해당하는 땅을 arrList 배열에 입력한 후에 마지막에 arrList 배열의 크기가 2개 이상일 때 평균을 내서 땅의 인구수를 평균으로 변경한다.

 

변경해준 후에는 isMove 변수를 true로 바꾸면 된다.

 

<최종코드>

import java.io.*;
import java.util.*;

public class Main {
    static int[] dx = {-1, 0, 1, 0};
    static int[] dy = {0, -1, 0, 1};
    static int[][] map;
    static boolean[][] visited;
    static int N, L, R, ans;
    static boolean isMove;
	
    public static class Position {
        int x;
        int y;
		
        public Position(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
	
    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());
            }
        }
		
        // 변경한 값이 없을 때까지 반복
        while (true) {
            visited = new boolean[N][N]; // 방문 유부
            isMove = false; // 변경 유무
			
            for (int i=0; i<N; i++) {
                for (int j=0; j<N; j++) {
                    if (!visited[i][j]) bfs(i, j);
                }
            }
			
            if (!isMove) break;
            ans++;
        }
		
        System.out.println(ans);
    }
	
    public static void bfs(int x, int y) {
        Queue<Position> q = new LinkedList<>();
        ArrayList<Position> arrList = new ArrayList<>(); // 인구수를 평균내기 위한 배열
		
        arrList.add(new Position(x, y)); // 시작 땅 추가
        q.add(new Position(x, y));
        visited[x][y] = true;
        int sum = map[x][y];
		
        while(!q.isEmpty()) {
            Position now = q.poll();
			
            for (int i=0; i<4; i++) {
                int nx = now.x + dx[i];
                int ny = now.y + dy[i];
				
                if (nx < 0 || nx > N-1 || ny < 0 || ny > N-1 || visited[nx][ny]) continue;
				
                int sumxy = Math.abs(map[nx][ny] - map[now.x][now.y]);
				
                // 조건에 해당하는 땅 (인구수 차이가 L과 R사이)
                if (L <= sumxy && sumxy <= R) {
                    sum += map[nx][ny];
					
                    arrList.add(new Position(nx, ny));
                    q.add(new Position(nx, ny));
                    visited[nx][ny] = true;
                }
            }
        }
		
        // 변경할 값이 존재할 경우
        if (arrList.size() > 1) {
            int num = sum / arrList.size();
            for (int i=0; i<arrList.size(); i++) {
                map[arrList.get(i).x][arrList.get(i).y] = num;
            }
			
            isMove = true;
        }
    }
}
반응형