Algorithm(BOJ, Python)/BFS&DFS

[백준_16234] 인구이동 python

kurooru 2022. 8. 31. 19:21

시뮬레이팅과 bfs를 적절히 사용하여 해결해야 한다.

# n, l, r 입력
n, l, r = map(int, input().split())

# world 입력
world = [
    list(map(int, input().split()))
    for _ in range(n)
]

# 함수돌

# in_range(x, y)
def in_range(x, y):
    return 0 <= x and x < n and 0 <= y and y < n

# bfs
def bfs():

    global world, visited
    
    # 연합된 나라들의 좌표를 담아 줄 리스트
    union_pos = []

    # 연합된 나라들의 인구수 합 측정용
    union_population = 0

    while q:
        x, y = q.popleft()
        # 연합된 나라들 좌표 넣어주기
        union_pos.append((x, y))
        # 연합된 나라들 인구수 측정해주기
        union_population += world[x][y]

        dxs, dys = [-1, 1, 0, 0], [0, 0, -1, 1]
        for dx, dy in zip(dxs, dys):
            nx, ny = x + dx, y + dy
            # 주변 나라의 국경이 열릴 수 있으면,
            if in_range(nx, ny) and l <= abs(world[x][y] - world[nx][ny]) <= r and not visited[nx][ny]:
                # 방문 처리 해 주고
                visited[nx][ny] = 1
                # 큐에 넣어주기
                q.append((nx, ny))
    
    # 새로운 인구수
    new_population = int(union_population / len(union_pos))

    # 인구 이동시켜주기
    for u_x, u_y in union_pos:
        world[u_x][u_y] = new_population

# is_open(x, y)
def is_open(x, y):
    # 상 하 좌 우 중
    dxs, dys = [-1, 1, 0, 0], [0, 0, -1, 1]
    for dx, dy in zip(dxs, dys):
        # 주변 영역의 좌표
        nx, ny = x + dx, y + dy
        # 범위 내에 있는 한 곳이라도 그 좌표와 값과 현재 값의 차가 l이상 r이하라면
        if in_range(nx, ny) and l <= abs(world[nx][ny] - world[x][y]) <= r:
            return True
    # 다 돌았는데도, 차가 l이상 r이하인적이 없으면 실패
    return False
        

# all_done()
def all_done():
    # world를 돌면서
    for i in range(n):
        for j in range(n):
            # 하나라도 주변에 경계선이 열리면,
            if is_open(i, j):
                # 실패
                return False
    # 다 돌았는데도 경계선이 열린 적이 없으면 성공
    return True

# 설계
# 큐 사용준비
from collections import deque
q = deque()

# ans 설정
ans = 0

while True:
    
    # 만약 인구 이동이 일어나지 않는다면(경계선이 하나도 열리지 않는다면)
    if all_done():
        # 정답 출력하고,
        print(ans)
        # 반복종료
        break

    # 인구 이동이 일어난다면 (경계선이 하나라도 열린다면)
    else:
        # 이동 횟수 증가
        ans += 1
        
        # visited 배열 선언 및 초기화
        visited = [
            [0] * n
            for _ in range(n)
        ]

        # world 돌면서
        for i in range(n):
            for j in range(n):
                # 방문하지 않은 곳을 발견하면,
                if not visited[i][j]:
                    # 방문 처리 해 주고,
                    visited[i][j] = 1
                    # 그 좌표를 큐에 넣어주고
                    q.append((i, j))
                    # bfs 돌려주기
                    bfs()