알고리즘/BOJ
[백준] 17471_게리맨더링
엉아_
2021. 10. 13. 20:39
728x90
📕 문제
https://www.acmicpc.net/problem/17471
17471번: 게리맨더링
선거구를 [1, 4], [2, 3, 5, 6]으로 나누면 각 선거구의 인구는 9, 8이 된다. 인구 차이는 1이고, 이 값보다 더 작은 값으로 선거구를 나눌 수는 없다.
www.acmicpc.net
💡 풀이법
1. 1~N-1개의 조합을 만든다.
(여기서 만든 조합은 한 선거구가 되고, 나머지 번호들이 다른 선거구가 된다)
2. for문을 돌며 구한 조합에 대해서 dfs를 돌린다. 우선 조합에 들어있는 번호를 visited에 담고, 방문할 때마다 visited에서 빼는 식으로 모두 방문가능한지 구한다. (dfs가 다 돌고 visited가 비었다면 조합에 있는 모든 구역이 인접한것)
3. dfs를 돌며 방문체크와 동시에 total에 선거구의 인구수를 더해서 합을 구한다.
4. 모두 방문 가능하다면 다른 선거구의 인구의 합(전체 인구수- total)과 현재 선거구의 차이(diff)를 구한다.
5. 차이가 ans보다 작다면 다름 선거구에 대해서 모두 인접한지 확인한다.
( 차이가 ans보다 작지 않다면 답이 될수 없기 때문에 두 선거구들이 각자 인접해있더라도 굳이 봐줄 필요가 없음)
6. 다른 선거구도 모두 인접하다면 그때 ans를 두 선거구의 인구수 차이로 바꾼다.
from itertools import combinations
def dfs(n):
total = 0
stack = [n]
visited.remove(n)
while stack:
v = stack.pop()
total += population[v]
for j in node[v]:
if j in visited:
visited.remove(j)
stack.append(j)
return total
N = int(input())
population = [0] + list(map(int, input().split()))
population_sum = sum(population)
node = {}
ans = 9999
for i in range(1, N+1):
lst = list(map(int, input().split()))
node[i] = lst[1:]
area = [i for i in range(1, N+1)]
for i in range(1, N):
for item in combinations(area, i):
visited = list(item)
t = dfs(visited[0])
if not visited:
diff = abs((population_sum - t)-t)
if diff < ans:
visited = list(set(area) - set(item))
dfs(visited[0])
if not visited:
ans = diff
if ans == 9999:
print(-1)
else:
print(ans)