image

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 실행
      • 연합이 형성되면 movedTrue로 설정
    • 이번 턴에 이동이 없었다면 반복 종료
    • 이동이 있었으면 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())

댓글남기기