백준 17471. 게리맨더링(python)
2023. 5. 8. 01:05ㆍ알고리즘/백준
17471번: 게리맨더링
선거구를 [1, 4], [2, 3, 5, 6]으로 나누면 각 선거구의 인구는 9, 8이 된다. 인구 차이는 1이고, 이 값보다 더 작은 값으로 선거구를 나눌 수는 없다.
www.acmicpc.net
입력
- 첫째 줄에 구역의 개수 N이 주어진다.
- 둘째 줄에 구역의 인구가 1번 구역부터 N번 구역까지 순서대로 주어진다.
- 셋째 줄부터 N개의 줄에 각구역과 인접한 구역의 정보가 주어진다.
- A가 B와 인접하면 B도 A와 인접하다.
문제 풀이
- 지역구가 정확히 둘로 나뉘었을 때, 두 지역구 인구차의 최솟값을 구해야한다.
- 또한 두 지역구로 나누지 못할 때는 -1을 출력하면 된다.
N = int(input())
popul = [*map(int, input().split())]
jun = sum(popul)
arr = [0]*(N+1)
check = [0]*(N+1)
minn = 21e10
flag = 0
for i in range(1, N+1):
n, *arr[i] = [*map(int, input().split())]
- 입출력을 받는다.
- jun 은 전체 인구수를 나타내고, check 배열은 각 구역이 몇 번 지역구로 포함될지 표시하는 리스트이다.
for i in range(1<<N):
cnt = 0 # 1번 지역구 개수
start1 = 0 # 1번 지역구 탐색 시작할 번호 저장할 변수
for j in range(N):
if i & (1<<j): # 지역구가 나눠지는 모든 경우의 수
check[j+1] = 1 # 1번 지역구 표시
start1 = j + 1
cnt += 1
else:
check[j+1] = 2 # 2번 지역구 표시
start2 = j + 1
- 두 지역구로 나뉠 수 있는 모든 경우를 비교해야하기에 비트 연산을 통해 모든 경우를 나타내었다.
if cnt == 0 or cnt == N:
continue
else:
s1 = bfs(start1, cnt, 1, 0) # 1번 지역구 모두 이어져 있는지 검사
s2 = bfs(start2, N-cnt, 2, 0) # 2번 지역구 모두 이어져 있는지 검사
if s1:
if s2: # 두 지역구 모두 0 반환되지 않았으면
flag = 1 # flag 킴
minn = min(minn, abs(jun-2*s1)) # 최솟값과 인구 차이 비교하여 갱신
- 한 지역구로 모든 구역이 포함된다면, 검사할 필요가 없다.
- 그렇지 않은 경우에는 위에서 표시한 지역구들이 각각 모두 이어져 있는지 bfs를 통해 검사하였다.
- bfs 함수에서 반환 받은 값이 둘 다 0이 아니면, 두 구역으로 나뉠 수 있으므로, 기존의 최솟값과 구한 인구 차를 비교하여 갱신한다.
- bfs 함수의 구조는 다음과 같다.
def bfs(v, cnt, team, sum): # team - 지역구(1 or 2), sum - 인구 합
visited = [0]*(N+1)
queue = deque()
queue.append(v)
visited[v] = 1
cnt -= 1
sum = popul[v-1]
while queue:
now = queue.popleft()
for i in arr[now]:
if visited[i] == 0 and check[i] == team: # 방문하지 않았고 같은 지역구이면 방문
visited[i] = 1
queue.append(i)
cnt -= 1
sum += popul[i-1]
if cnt != 0: # 만약 방문 못한 곳 있으면 0 반환
return 0
else: # 그렇지 않으면 인구 합 반환
return sum
- bfs 알고리즘 뼈대에 같은 지역구인지 판별하고, 모든 지역구를 방문했는지 체크하는 코드를 추가하였다.
- 만약 모든 지역구가 이어져있지 않아, 방문하지 못한 구역이 있다면 0을 반환, 그렇지 않다면 인구의 합을 반환한다.
if flag == 1: # flag 켜졌으면
print(f'{minn}') # 최솟값 출력
else:
print(-1)
- 만약 최솟값 갱신이 한 번이라도 됐다면, 두 구역으로 나뉠 수 있는 경우가 존재하는 것이므로 인구 차의 최솟값을 출력한다.
- 그렇지 않다면 -1을 출력한다.

'알고리즘 > 백준' 카테고리의 다른 글
| 백준 2116. 주사위 쌓기(python) (1) | 2023.05.01 |
|---|---|
| 백준 17472. 다리 만들기 2(python) (0) | 2023.04.23 |
| 백준 17281. ⚾ (0) | 2023.04.16 |
| 백준 4991. 로봇 청소기(python) (0) | 2023.04.16 |