https://www.acmicpc.net/problem/17471

 

17471번: 게리맨더링

선거구를 [1, 4], [2, 3, 5, 6]으로 나누면 각 선거구의 인구는 9, 8이 된다. 인구 차이는 1이고, 이 값보다 더 작은 값으로 선거구를 나눌 수는 없다.

www.acmicpc.net

조합을 통한 완전탐색 + 유니온파인드로 접근하였다.


접근 방법

입력으로 주어지는 구역의 최대개수는 10이다. 따라서 각 구역이 두 가지 선거구로 선택되는 경우의 수를 계산하면 2^10 즉 1024의 경우의 수가 발생. 이후 각 조건에서 유니온 파인드를 수행한다.

유니온 파인드에서 두 노드가 결합되는 조건은 서로 인접하며 정해진 선거구가 같은 경우만 결합하는 것으로 하였다. 마지막으로 컴포넌트의 수가 2인 경우만 각 선거구의 인구수를 확인하여 정답을 반영하면 된다.


정답 코드

import Foundation
let N = Int(readLine()!)!
var population = readLine()!.split(separator: " ").map{Int($0)!}
var total = population.reduce(0, +)
var edges = [(u:Int, v:Int)]()
var ans = Int.max
for u in 0..<N{
let info = readLine()!.split(separator: " ").map{Int($0)!}
let n = info[0]
if n == 0{ continue }
for i in 1...n{ edges.append((u,info[i]-1))}
}
var list = [[String]]()
func btk(team:[String]){
var team = team
if team.count == N{
list.append(team)
return
}
team.append("R")
btk(team: team)
team.removeLast()
team.append("B")
btk(team: team)
}
btk(team: [])
for team in list{
var arr = population.map{-1*$0}
var cnt = N
var red = 0
var blue = 0
for i in 0..<N{
if team[i] == "R"{
red += population[i]
}else{
blue += population[i]
}
}
func root(of node:Int) -> Int{
if arr[node] < 0{ return node }
arr[node] = root(of: arr[node])
return arr[node]
}
func union(a:Int, b:Int){
let A = root(of: a)
let B = root(of: b)
if team[a] != team[b] { return }
if A==B { return }
arr[A] += arr[B]
arr[B] = A
cnt -= 1
}
for edge in edges {
union(a: edge.u, b: edge.v)
}
if cnt == 2{
ans = min(ans,abs(red-blue))
}
}
print(ans==Int.max ? -1:ans)
view raw 17471.swift hosted with ❤ by GitHub

'Problem Solving > BOJ' 카테고리의 다른 글

[13397] 구간 나누기 2  (0) 2024.02.28
[8983] 사냥꾼  (0) 2024.02.19
[1700] 멀티탭 스케줄링  (0) 2024.01.30
[23286] 허들 넘기  (0) 2024.01.18
[5582] 공통 부분 문자열  (0) 2024.01.12

+ Recent posts