문제
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번 보다 작거나 같은 입력만 주어진다.
출력
인구 이동이 며칠 동안 발생하는지 첫째 줄에 출력한다.
풀이 과정
1. 먼저, NxN 크기에 있는 나라들이 서로 국경선을 열 수 있는지 확인한다. ( 인접한 나라의 인구 차가 L명 이상, R명 이하인지 확인한다. )
2. 만약 국경선을 열 수 있다면, 해당 나라와의 간선 정보를 추가하여 나라끼리 이어준다. 다른 나라와도 국경선을 열어 연합을 했다면 간선을 통하여 같은 연합임을 확인할 수 있다.
3. 국경선을 연 후, 연합 범위를 탐색한다. 연합이라고 해도 다른 연합일 수 있으니, BFS 를 이용하여 특정 연합의 인구 수와 연합에 참여한 나라 수를 동시에 센다.
4. 연합 범위를 탐색했다면, 그 연합의 인구 수와 참여한 나라 수로 각 칸의 인구 수를 계산하여, 다시 BFS 를 이용해 다시 계산된 인구 수를 덮어쓰도록 전파한다.
5. 모든 연합에 대한 인구 이동을 끝냈다면, 1번으로 돌아가서 인구 이동을 할 수 있는지를 확인한다.
인구 이동을 다음과 같이 구현하여, 인구 이동을 한 횟수를 출력한다.
import sys
from collections import deque
input = sys.stdin.readline
N, L, R = map(int, input().rstrip().split())
A = [list(map(int, input().rstrip().split())) for _ in range(N)]
Aable = [[[[0, 0, 0, 0], 0] for _ in range(N)] for _ in range(N)]
row = [-1, 0, 1, 0]
col = [0, 1, 0, -1]
time = 0
while True:
done = 1
for i in range(N):
for j in range(N):
Aable[i][j][1] = 0
for d in range(4):
Aable[i][j][0][d] = 0
ny = i + row[d]
nx = j + col[d]
if 0 <= ny < N and 0 <= nx < N and L <= abs(A[ny][nx] - A[i][j]) <= R:
done = 0
Aable[i][j][0][d] = 1
Aable[ny][nx][0][(d+2)%4] = 1
if done: break
time += 1
for i in range(N):
for j in range(N):
for k in range(4):
if Aable[i][j][0][k] == 1 and Aable[i][j][1] == 0:
queue = deque()
queue.append([i, j])
Aable[i][j][1] = 1
sums = A[i][j]
cnt = 1
while queue:
now = queue.popleft()
for d in range(4):
ny = now[0] + row[d]
nx = now[1] + col[d]
if 0 <= ny < N and 0 <= nx < N and Aable[now[0]][now[1]][0][d] == 1 and Aable[ny][nx][1] == 0:
Aable[ny][nx][1] = 1
sums += A[ny][nx]
cnt += 1
queue.append([ny, nx])
queue = deque()
queue.append([i, j])
Aable[i][j][1] = 2
persons = sums // cnt
A[i][j] = persons
while queue:
now = queue.popleft()
for d in range(4):
ny = now[0] + row[d]
nx = now[1] + col[d]
if 0 <= ny < N and 0 <= nx < N and Aable[now[0]][now[1]][0][d] == 1 and Aable[ny][nx][1] == 1:
Aable[ny][nx][1] = 2
A[ny][nx] = persons
queue.append([ny, nx])
print(time)
'-- 예전 기록 > BOJ' 카테고리의 다른 글
[ BOJ ] 2225 : 합분해 ( GOLD 5 ) / Python (0) | 2023.12.06 |
---|---|
[ BOJ ] 12100 : 2048 (Easy) ( GOLD 2 ) / Python (0) | 2023.12.05 |
[ BOJ ] 1715 : 카드 정렬하기 ( GOLD 4 ) / Python (0) | 2023.12.03 |
[ BOJ ] 2110 : 공유기 설치 ( GOLD 4 ) / C, Python (0) | 2023.12.03 |
[ BOJ ] 1107 : 리모컨 ( GOLD 5 ) / Python (0) | 2023.12.02 |