코드굽는 타자기

Baekjoon[16234] - 인구 이동 본문

알고리즘/깊이&너비 우선 탐색(DFS&BFS)

Baekjoon[16234] - 인구 이동

bright-jun 2020. 3. 2. 16:31

링크

 

16234번: 인구 이동

N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접한 나라 사이에는 국경선이 존재한다. 모든 나라는 1×1 크기이기 때문에, 모든 국경선은 정사각형 형태이다. 오늘부터 인구 이동이 시작되는 날이다. 인구 이동은 다음과 같이 진행되고, 더 이상 아래 방법에 의해 인구 이동이 없을 때까지 지속된다. 국경선을 공유하는 두 나라의 인구 차이가 L명

www.acmicpc.net

 

문제설명

  • 인접 칸과의 값 차이가 특정 범위 안이면 연결되어 인구가 이동하여 평균이 된다.

문제풀이

  • 그래프의 연결성 문제, DFS가 좋대서 DFS로품.

문제코드

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class Main16234 {

    public static int[][] dir = {
            {-1,0},
            {1,0},
            {0,-1},
            {0,1}
    };

    public static int Ans;
    public static int Temp;
    public static int Avg;
    public static boolean moved;

    public static int N;
    public static int L;
    public static int R;
    public static int[][] map;
    public static boolean[][] visited;
    public static ArrayList<int[]> link = new ArrayList<int[]>();

    public static void DFS(int[]rc) {
        visited[rc[0]][rc[1]]=true;
        Temp+=map[rc[0]][rc[1]];
        link.add(rc);

        int nr;
        int nc;
        int diff;
        for (int d = 0; d < 4; d++) {
            nr = rc[0] + dir[d][0];
            nc = rc[1] + dir[d][1];
//            경계 내에서, 다음칸이 방문 가능할 때, 옆 칸과 값 차이가 L과 R사이
            if(nr>=0 && nr<N && nc>=0 && nc<N && !visited[nr][nc]) {
                diff = Math.abs(map[rc[0]][rc[1]]-map[nr][nc]);
                if(diff>=L && diff<=R) {
                    DFS(new int[] {nr,nc});
                }
            }
        }
    }

    public static void main(String[] args) throws IOException {
        System.setIn(new FileInputStream("res/baekjoon/16234.txt"));
        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 lsize;
        int[] now;
        while(true) {
            moved=false;
            visited = new boolean[N][N];
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < N; j++) {
                    if(!visited[i][j]) {
                        link.clear();
                        Temp=0;
                        DFS(new int[] {i,j});
                        lsize = link.size();
                        Avg = Temp/lsize;
                        if(lsize>1) {
                            moved=true;
                            for (int l = 0; l < lsize; l++) {
                                now = link.get(l);
                                map[now[0]][now[1]]=Avg;
                            }
                        }
                    }
                }
            }
            if(moved) {
                Ans++;
            }
            else {
                break;
            }
        }

        System.out.println(Ans);
//        초기화
        Ans=0;
    }
}

아쉬운점

  • O(N) 고려안했음
    • N=50, Map=2500, DFS O(N)은 몇이지?
  • while문에서 움직여야 Ans++인데 안움직여도 Ans++하게 했었음.
  • 다음칸 탐색할 때, 옆 칸과의 차이 diff를 구할 때 경계검사 이전에 정의해서 경계검사안하고 터지는 경우 생겼었음.

잘한점

  • 시간(25분)
  • 그래프의 연결성 문제인 것을 알았음
  • 연결된 그래프들은 list에 저장 후 따로 평균치 넣어주기
  • 연결시킨 그래프들 제외하기위해서 visit 고려했음
Comments