티스토리 뷰

알고리즘/BOJ

[BOJ-16234] 인구이동

개발하는 후딘 2020. 3. 18. 07:50
728x90
반응형

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

 

16234번: 인구 이동

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

www.acmicpc.net


[풀이]

예제 5번을 잘 이해해보고 풀어보자.

N=4, L=10, R= 50

A=[[10 ,100, 20, 90], [80, 100, 60, 70], [70, 20, 30, 40], [50, 20, 100, 10]]

출력: 3

 

먼저 각 지역 인구차이가 L~R을 만족하는 그룹들을 먼저 찾는다.

그룹이 한개라면 문제에서 보여준 예제대로 (연합의 인구수)/(연합을 이루는 칸 개수) 로 

A값을 업데이트하면된다.

 

그렇다면 그룹이 여러개가 존재한다면 어떻게 해야할까?

마찬가지로 각 그룹별로 (통합후인구합)/(연결된 네모칸 개수) 로 A의 값을 업데이트한다.

 

A배열 (인구이동 횟수 0회)

A배열이 위의 그림과 같다.

먼저 현위치의 상/하/좌/우 중 하나가 L과 R사이라면

BFS연산을 한다.

 

현위치 (y,x)라 할때, 현위치가 아직 방문하지 않은 상태여야한다.

현위치의 상/하/좌/우 위치를 (nexty, nextx)라 하자

L(10)<= abs(A[nexty][nextx]-A[y][x])<=R (50) 인 것을 만족한 상/하/좌/우 위치가 하나라도 있다면

위치 (y,x)를 시작점으로 BFS연산을 한다는 것이다.

그리고 하나라도 있기때문에, 인구이동 한번 하게 된다.

인구이동을 한뒤에 앞으로도 계속 이동할지 따져야한다.

 

여기서 BFS연산도 마찬가지로

현위치의 상/하/좌/우 가 아직 방문되지 않은 상태이고

조건 L(10)<= abs(A[nexty][nextx]-A[y][x])<=R (50)을 만족하는지 확인해야한다.

그러면 초기배열 A=[[10 ,100, 20, 90], [80, 100, 60, 70], [70, 20, 30, 40], [50, 20, 100, 10]]은 

위의 그림과 같이 조건을 만족하는 연결그룹 1개를 얻을 수 있다.

 

그리고 BFS함수를 실행중 현위치의 방문여부를 따진 뒤

방문 후에 현재위치(y,x, A[y][x])를 unions라는 리스트에 저장을했다. 

unions의 목적은 나중에 연결된 그룹들의 값을 갱신해야한다.

 

연합의 인구수=unions의 2번째원소들 원소값 총합

연합을 이루고 있는 칸의개수= len(unions)

갱신값= int(연합의 인구수 / 연합을 이루고 있는 칸의 개수)

 

 

 

 

 

 

 


[코드]

import sys
from collections import deque
input=sys.stdin.readline
q=deque()

#상/하/좌/우
dy=(-1,1,0,0)
dx=(0,0,-1,1)

#입력
N,L,R=map(int, input().strip().split())
A=[]
for _ in range(N):
    A.append([*map(int, input().strip().split())])

def isRange(y,x):
    global N
    if (y>=0 and y<N) and (x>=0 and x<N):
        return True
    return False

def bfs(y,x):
    global L,R,A,N, visited
    unions=[]
    q.append((y,x))
    while q:
        y,x=q.popleft()
        if not visited[y][x]:
            visited[y][x]=True
            unions.append((y,x,A[y][x]))
            for i in range(4):
                nexty, nextx=y+dy[i], x+dx[i]
                if isRange(nexty, nextx):
                    if (L<=abs(A[nexty][nextx]-A[y][x])<=R) and (not visited[nexty][nextx]):
                        q.append((nexty,nextx))
           
    union_sum=0
    for i in range(len(unions)):
        union_sum+=unions[i][2]

    union_sum=int(union_sum/len(unions))
    for i in range(len(unions)):
        A[unions[i][0]][unions[i][1]]=union_sum


def solution():
    global N,L,R,A, visited
    #나라가 1개밖에 없으므로 인구이동할 필요가 없다.
    if N==1:
        return 0
    
    result=0
    while True:
        visited=[[False]*N for _ in range(N)]
        keep_loop=False
        for y in range(N):
            for x in range(N):
                if not visited[y][x]:
                    cnt=0
                    for i in range(4):
                        nexty=y+dy[i]
                        nextx=x+dx[i]
                        if isRange(nexty, nextx):
                            if L<=abs(A[nexty][nextx]-A[y][x])<=R:
                                cnt+=1
                                break
                    #상/하/좌/우 중  현재위치의 인구수차이가 L~R사이가 최소 한개라도 있다면.
                    if cnt>0:
                        bfs(y,x)
                        keep_loop=True
       
        if not keep_loop:
            break
        result+=1
    return result
    
def main():
    print(solution())
    
if __name__=='__main__':
    main()

 

728x90
반응형

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

[BOJ-14500] 테트로미노  (0) 2020.03.21
[BOJ-14499] 주사위 굴리기  (0) 2020.03.21
[BOJ-1062] 가르침  (0) 2020.03.18
[BOJ-1966] 프린터 큐  (0) 2020.03.17
[BOJ-14501] 퇴사  (0) 2020.03.16
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함