본문 바로가기

Algorithm/[이코테] 알고리즘 유형별 기출문제

[이코테] DFS/BFS 구현문제 - 인구 이동 python

난이도 : ●●○ | 풀이 시간 : 40분 | 시간 제한 : 2초 | 메모리 제한 : 512MB | 기출 : 삼성전자 SW 역량테스트

 

문제

  • NxN 크기의 땅이 있고, 땅은 1x1개의 칸을 차지한다.
  • 각 땅에는 나라가 하나씩 존재한다.
  • r행 c열에 있는 나라의 인구수는 A[r][c]이다.
  • 인접한 나라 사이에는 국경선이 있다.
  • 오늘부터 인구이동이 시작된다.
    • 국경선을 공유하는 나라의 인구 차이가 L이상 R이하라면 두 나라가 공유하는 국경선을 오늘 하루 동안 연다.
    • 위 조건에 의해 열어야 하는 국경선이 모두 열리면 인구 이동을 시작한다.
    • 국경선이 열려있어 이동할 수 있으면 그 나라를 오늘 하루 동안 연합이라고 한다.
    • 연합을 이루는 각 나라의 인구수는 (연합의 인구수)/(연합을 이루고 있는 나라의 개수)가 되고, 편의상 소수점은 버린다.
    • 연합을 해체하고 모든 국경선을 닫는다.
  • 각 나라의 인구수가 주어질 때 인구 이동이 몇 번 발생하는지 구하는 프로그램을 작성하라.

 

입력조건

  • 첫째 줄에 N, L, R이 주어진다.(1<=N<=50, 1<=L<=R<=100)
  • 둘째 줄부터 N개의 줄에 각 나라의 인구수가 주어진다. r행 c열에 주어지는 정수는 A[r][c]의 값이다. ()<=A[r][c]<=100)
  •  인구 이동 횟수가 2,000번보다 작거나 같은 입력만 주어진다.

출력조건

  • 인구 이동이 몇 번 발생하는지 첫째 줄에 출력한다.

입력예시

2 20 50
50 30
20 40

출력예시

1

 

아이디어

  • BFS로 상하좌우로 인접한 나라를 탐색하면서 연합국의 수, 연합의 총 인구수를 증가시킨다.
  • 연합에 소속된 모든 나라의 인구수를 (연합의 총인원//연합국의 수)로 갱신한다.

 

코드

from collections import deque
n,l,r = map(int,input().split())
graph = []
for _ in range(n):
graph.append(list(map(int,input().split())))
dx = [-1,1,0,0]
dy = [0,0,-1,1]
total_cnt = 0
def bfs(index,x,y):
q = deque()
q.append((x,y))
# 연합을 생성함
unite = []
# 연합에 현재 국가를 추가함
unite.append((x,y))
# 연합번호를 union 리스트에 저장함
union[x][y]=index
# unite에 소속된 국가의 개수
cnt = 1
# unite에 소속된 연합국가의 총 인구수
summary = graph[x][y]
while q:
x,y = q.popleft()
for i in range(4):
nx = x+dx[i]
ny = y+dy[i]
# 범위 내에 있고 아직 연합에 소속되지 않은 국가라면
if 0<=nx<n and 0<=ny<n and union[nx][ny]==-1:
# 인접한 국가와의 인구수 차이가 l이상 r이하라면
if l<=abs(graph[x][y]-graph[nx][ny])<=r:
# 큐에 추가함
q.append((nx,ny))
# 연합번호를 기록함
union[nx][ny] = index
# 총 인구수를 증가시킴
summary+=graph[nx][ny]
# unite에 소속된 국가의 수를 1 증가시킴
cnt += 1
# 연합에 추가함
unite.append((nx,ny))
# 연합에 소속된 국가들에 대해서
for i,j in unite:
# 인구수를 업데이트함
graph[i][j] = summary//cnt
while True:
# 각 국가들이 소속된 연합번호를 기록할 리스트.
# 방문여부를 확인하는 데에 사용됨
union = [[-1]*n for _ in range(n)]
# 처음 생성되는 연합의 번호는 0
index = 0
# 아직 아무런 연합에 소속되지 않은 국가라면 그 위치에서부터 bfs를 수행함
# 한 연합이 생성된 것이니 연합번호인 index를 1 증가시킴
for i in range(n):
for j in range(n):
if union[i][j]==-1:
bfs(index,i,j)
index +=1
# 연합이 n*n개가 생성되었다 == 더이상 인구이동이 없다는 뜻이므로 반복 종료
if index==n*n:
break
# 인구이동 횟수를 1 증가시킴
total_cnt +=1
print(total_cnt)

 

후기

  • 상하좌우로 인접해있는 나라가 연합이 될 수 있다는 걸 한 연합의 크기가 최대 5라는 것으로 잘못 이해했다...
  • 더이상 이동이 일어나지 않을 때까지 반복한다는 걸 어떻게 구현해야 하는지 감을 못잡았다. 

 

출처

이것이 취업을 위한 코딩테스트다 with 파이썬