본문 바로가기
Python/백준

백준 인구이동 [16324] 파이썬(Python) 코드 + 해설

by Guardy 2024. 11. 1.
728x90

백준 인구이동 16324 문제

문제 설명

N×N 크기의 땅이 있다. 각 땅에는 나라가 하나씩 존재하며, 각 나라에는 인구수가 있다. 인접한 나라 사이에는 국경선이 있고, 인구 이동은 다음과 같은 과정으로 진행된다:

  1. 국경선 열기: 국경선을 공유하는 두 나라의 인구 차이가 L명 이상, R명 이하라면 국경선을 연다.
  2. 인구 이동: 국경선이 열려서 연결된 나라들은 연합을 이루고, 연합 내의 인구는 (연합의 총 인구수) / (연합을 이루는 칸의 개수)로 동일하게 분배된다. 소수점은 버린다.
  3. 국경선 닫기: 모든 국경선을 닫는다.

이 과정이 더 이상 인구 이동이 없을 때까지 반복된다. 인구 이동이 발생하는 일수를 구하는 것이 문제의 목표다.

문제 접근

이 문제는 BFS(너비 우선 탐색)를 활용한 시뮬레이션 문제다. 각 단계별로 인구 이동이 가능한지 확인하고, 가능한 경우 인구를 이동시켜야 한다.

핵심 아이디어

  • 시뮬레이션 반복: 인구 이동이 발생하지 않을 때까지 하루씩 시뮬레이션을 반복한다.
  • BFS를 통한 연합 찾기: 각 나라를 방문하면서 인접한 나라와의 인구 차이가 조건에 맞는 경우 연합을 형성한다.
  • 인구 이동 처리: 형성된 연합에 대해 인구를 재분배한다.
  • 인구 이동 여부 확인: 하루 동안 인구 이동이 발생했는지 여부를 확인하여 시뮬레이션 종료 조건을 판단한다.

코드 구현

1. 입력 및 초기화

import sys
from collections import deque

input = sys.stdin.readline

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

 

  • N: 땅의 크기 (N x N)
  • L, R: 인구 차이의 최소값과 최대값
  • A: 각 나라의 인구 수를 저장하는 2차원 배열

2. 방향 설정

dx = [-1, 1, 0, 0]  # 상하좌우 이동을 위한 x 좌표 변화량
dy = [0, 0, -1, 1]  # 상하좌우 이동을 위한 y 좌표 변화량

 

  • BFS 탐색 시 상하좌우로 이동하기 위한 방향 설정이다.

3. BFS 함수 구현

def bfs(x, y, visited):
    queue = deque()
    queue.append((x, y))
    union = [(x, y)]
    visited[x][y] = True
    total_population = A[x][y]
    
    while queue:
        x, y = queue.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0 <= nx < N and 0 <= ny < N and not visited[nx][ny]:
                population_diff = abs(A[x][y] - A[nx][ny])
                if L <= population_diff <= R:
                    visited[nx][ny] = True
                    queue.append((nx, ny))
                    union.append((nx, ny))
                    total_population += A[nx][ny]
    return union, total_population
  • bfs 함수는 (x, y) 좌표에서 시작하여 연합을 찾는다.
  • visited 배열을 이용하여 이미 방문한 나라를 체크한다.
  • union 리스트에 연합에 속한 나라의 좌표를 저장한다.
  • total_population은 연합의 총 인구수를 저장한다.
  • BFS 탐색을 통해 인접한 나라를 확인하고, 인구 차이가 조건에 맞으면 연합에 추가한다.

4. 시뮬레이션 반복

days = 0

while True:
    visited = [[False]*N for _ in range(N)]
    is_moved = False  # 인구 이동 발생 여부
    for i in range(N):
        for j in range(N):
            if not visited[i][j]:
                union, total_population = bfs(i, j, visited)
                if len(union) > 1:
                    is_moved = True
                    new_population = total_population // len(union)
                    for x, y in union:
                        A[x][y] = new_population
    if not is_moved:
        break
    days += 1

 

  • days: 인구 이동이 발생한 일수를 저장한다.
  • 무한 루프를 통해 인구 이동이 발생하지 않을 때까지 시뮬레이션을 반복한다.
  • is_moved 변수를 통해 인구 이동이 발생했는지 여부를 체크한다.
  • 각 나라를 방문하면서 BFS를 통해 연합을 찾고, 연합의 인구를 재분배한다.
  • 인구 이동이 발생하지 않으면 루프를 탈출한다.

16324 인구이동 정답 코드(Python)

import sys
from collections import deque

input = sys.stdin.readline

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

dx = [-1, 1, 0, 0]  # 상하좌우
dy = [0, 0, -1, 1]

def bfs(x, y, visited):
    queue = deque()
    queue.append((x, y))
    union = [(x, y)]
    visited[x][y] = True
    total_population = A[x][y]
    
    while queue:
        x, y = queue.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0 <= nx < N and 0 <= ny < N and not visited[nx][ny]:
                if L <= abs(A[x][y] - A[nx][ny]) <= R:
                    visited[nx][ny] = True
                    queue.append((nx, ny))
                    union.append((nx, ny))
                    total_population += A[nx][ny]
    return union, total_population

days = 0

while True:
    visited = [[False]*N for _ in range(N)]
    is_moved = False
    for i in range(N):
        for j in range(N):
            if not visited[i][j]:
                union, total_population = bfs(i, j, visited)
                if len(union) > 1:
                    is_moved = True
                    new_population = total_population // len(union)
                    for x, y in union:
                        A[x][y] = new_population
    if not is_moved:
        break
    days += 1

print(days)

 

16324 인구이동 결과

16324 인구이동 제출 결과

 

도움이 되셨다면 공감과 댓글 부탁드립니다.

728x90