[백준][Python] 16234. 인구 이동
Gold Ⅳ 🔗16234. 인구 이동
📝문제 요약
문제
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번 보다 작거나 같은 입력만 주어진다.
출력
인구 이동이 며칠 동안 발생하는지 첫째 줄에 출력한다.
✏️문제 풀이
- 입력 받기
n
: 땅의 크기 (n × n)l
,r
: 인구 차이가 이 범위 내일 때 인접한 나라끼리 국경을 열 수 있음n
줄 동안 각 나라의 주어지는 인구 수를 2차원 리스트 graph에 저장
- 이동 방향 설정
- 상, 하, 좌, 우 4가지 방향
bfs()
: 한 나라에서 시작하여 연합 형성- 시작 위치
(x, y)
를 큐에 넣고 방문 처리 union
리스트에 연합을 이루는 좌표들을 저장- 큐가 빌 때까지 반복:
- 현재 위치에서 4방향 탐색
- 범위를 벗어나지 않고 방문하지 않은 위치에 대해 인구 차이를 계산
- 조건에 맞으면 해당 위치를 큐에 추가하고,
union
,total
,count
에 반영
- 연합이 형성된 경우, 그 안에 포함된 모든 나라의 인구 수를 평균으로 설정
- 만약 연합의 크기가 2 이상이면
True
반환 (인구 이동 발생 의미), 아니면False
- 시작 위치
solve()
: 시뮬레이션 수행 함수- 결과 변수
result
는 인구 이동이 일어난 날 수를 의미 - 무한 루프를 돌면서, 매 반복마다
visited
리스트를 초기화하고moved
변수를False
로 설정 - 모든 좌표를 돌면서, 방문하지 않은 곳에 대해 BFS 실행
- 연합이 형성되면
moved
를True
로 설정
- 연합이 형성되면
- 이번 턴에 이동이 없었다면 반복 종료
- 이동이 있었으면
result
를 1 증가시키고 다음 턴 실행 - 반복이 끝난 후
result
반환
- 결과 변수
- 인구 이동이 몇 번 일어났는지 출력
코드와 함께 보는 풀이
from collections import deque
# n: 땅의 크기, l: 인구 차이 최소, r: 인구 차이 최대
n, l, r = map(int, input().split())
# 각 칸의 초기 인구 수
graph = [list(map(int, input().split())) for _ in range(n)]
# 4방향(상, 하, 좌, 우) 이동을 위한 델타
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]
# 특정 위치(x, y)에서 BFS 탐색하며 연합 구성
def bfs(x, y, visited):
queue = deque([(x, y)]) # BFS 탐색용 큐
visited[x][y] = True # 현재 위치 방문 처리
union = [(x, y)] # 현재 연합에 속한 나라들 좌표 저장
total = graph[x][y] # 연합의 총 인구
count = 1 # 연합에 속한 나라 수
while queue:
x, y = queue.popleft()
# 4방향 탐색
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]:
# 인구 차이가 L 이상 R 이하라면 연합 가능
if l <= abs(graph[nx][ny] - graph[x][y]) <= r:
visited[nx][ny] = True
queue.append((nx, ny))
union.append((nx, ny))
total += graph[nx][ny]
count += 1
# 연합이 형성되었으면 인구 이동 (평균값)
for i, j in union:
graph[i][j] = total // count
# 연합이 2개 이상일 때만 인구 이동이 일어난 것으로 간주
return count > 1
# 전체 시뮬레이션 실행
def solve():
# 인구 이동이 발생한 날짜 수 초기화
result = 0
while True:
# 매번 새로운 방문 상태 초기화
visited = [[False] * n for _ in range(n)]
# 이번 턴에 인구 이동이 있었는지 여부
moved = False
# 전체 칸에 대해 BFS 실행
for i in range(n):
for j in range(n):
if not visited[i][j]:
if bfs(i, j, visited):
# 이동이 발생했음을 표시
moved = True
# 더 이상 이동할 수 없으면 종료
if not moved:
break
# 인구 이동 하루 지나감
result += 1
return result
# 총 며칠 동안 인구 이동이 있었는지 출력
print(solve())
💯제출 코드
from collections import deque
n, l, r = map(int, input().split())
graph = [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([(x, y)])
visited[x][y] = True
union = [(x, y)]
total = graph[x][y]
count = 1
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(graph[nx][ny] - graph[x][y]) <= r:
visited[nx][ny] = True
queue.append((nx, ny))
union.append((nx, ny))
total += graph[nx][ny]
count += 1
for i, j in union:
graph[i][j] = total // count
return count > 1
def solve():
result = 0
while True:
visited = [[False] * n for _ in range(n)]
moved = False
for i in range(n):
for j in range(n):
if not visited[i][j]:
if bfs(i, j, visited):
moved = True
if not moved:
break
result += 1
return result
print(solve())
댓글남기기