[백준] 16234_인구이동 python

김동완·2022년 4월 30일
0

알고리즘

목록 보기
40/55
post-thumbnail
post-custom-banner

인구이동

문제

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

오늘부터 인구 이동이 시작되는 날이다.

인구 이동은 하루 동안 다음과 같이 진행되고, 더 이상 아래 방법에 의해 인구 이동이 없을 때까지 지속된다.

  • 국경선을 공유하는 두 나라의 인구 차이가 L명 이상, R명 이하라면, 두 나라가 공유하는 국경선을 오늘 하루 동안 연다.
  • 위의 조건에 의해 열어야하는 국경선이 모두 열렸다면, 인구 이동을 시작한다.
  • 국경선이 열려있어 인접한 칸만을 이용해 이동할 수 있으면, 그 나라를 오늘 하루 동안은 연합이라고 한다.
  • 연합을 이루고 있는 각 칸의 인구수는 (연합의 인구수) / (연합을 이루고 있는 칸의 개수)가 된다. 편의상 소수점은 버린다.
  • 연합을 해체하고, 모든 국경선을 닫는다.

각 나라의 인구수가 주어졌을 때, 인구 이동이 며칠 동안 발생하는지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N, L, R이 주어진다. (1 ≤ N ≤ 50, 1 ≤ L ≤ R ≤ 100)

둘째 줄부터 N개의 줄에 각 나라의 인구수가 주어진다. r행 c열에 주어지는 정수는 A[r][c]의 값이다. (0 ≤ A[r][c] ≤ 100)

인구 이동이 발생하는 일수가 2,000번 보다 작거나 같은 입력만 주어진다.

출력

인구 이동이 며칠 동안 발생하는지 첫째 줄에 출력한다.

해결방법

  • func3 전체 로직

    • 시간을 반환할 cnt를 만들고 방문배열을 만든다.
    • 인구를 변동해야할 국가들을 넣어줄 리스트를 만든다.
    • 시간이 얼마가 걸릴지 모르니 while문을 사용한다. 국가들을 돌면서 bfs를 돌린다.
    • 리스트가 비어있다면 변동할 국가가 없기 때문에 함수를 멈춘다.
    • 변동해야할 국가들이 있다면 리스트를 순회하며 국가 인구 합을 국가 수의 합으로 나눠 새롭게 인구를 배정해준다.
  • func1 절대값 반환

    • 간편하게 차이가 L이상 R 이하인지 Boolean으로 반환할 함수를 하나 만든다.
  • func2 bfs

  • 인접해 있으면서, 함수 결과가 True인 주위 나라들을 큐와 추가적인 리스트에 넣는다.

  • 큐가 끝나면 나라인구의 합과 조건을 만족했던 리스트를 반환한다.


from collections import deque

#절대값 T/F 
def func(x,y) :
    if L<=abs(x-y)<=R :
        return True
    else :
        return False


def bfs(r,c) :
    #최종 인구 합 
    res = grid[r][c]
    #큐 만들기 
    q = deque([(r,c)])
    #인접 국가 리스트 
    div_city = [(r,c)] 
    
    #방문표시 
    visited[r][c] = 1
    while q :
        cr,cc = q.popleft()
        #네방향을 돌면서 방문하지 않았고, 절대값 조건에 만족하면 큐에 넣고, 인접 국가 리스트에도 넣고 국가의 합에도 추가 
        for d in range(4) :
            nr = cr + dr[d]
            nc = cc + dc[d]
            if 0<=nr<N and 0<=nc<N and func(grid[cr][cc],grid[nr][nc]) and not visited[nr][nc] :
                visited[nr][nc] = 1 
                q.append((nr,nc))
                res += grid[nr][nc]
                div_city.append((nr,nc))
    #인접국가 길이와, 국가 합, 인접국가 리스트 리턴 
    return len(div_city),res,div_city



N,L,R = map(int,input().split())

grid = [list(map(int,input().split())) for _ in range(N)]

dr = [0,1,0,-1]
dc = [1,0,-1,0]

cnt = 0

cnt = 0
while True :
    #방문배열 
    visited = [[0]*N for _ in range(N)]
    #추후 인구를 재정렬할 리스트 
    lst = []
    #그리드를 돌면서 
    for r in range(N) :
        for c in range(N) :
            #bfs를 돌고 길이,인구합,인접국가리스트 리턴 
            l,res,d = bfs(r,c)
            #길이가 1보다 크면 재정렬 리스트에 포함 
            if l > 1 :
                lst.append((res,d))
    #재정렬 리스트가 비어있으면 더이상 움직일 수 없으니까 끝내기 
    if lst == [] :
        break 
    #재정렬 리스트가 있으면 재정렬 리스트를 돌면서 인구 재조정 
    for i in range(len(lst)) :
        #d = 인구 합 // 국가수 
        d = lst[i][0]//len(lst[i][1])
        for r,c in lst[i][1] :
            grid[r][c] = d
    #while문 끝날때마다 날짜 하루씩 추가 
    cnt += 1 
print(cnt)
profile
내가 공부한 내용들이 누군가에게 도움이 될지 몰라서 쓰는 벨로그
post-custom-banner

0개의 댓글