[게리맨더링 _ 17471]
* 조건
- 구역의 개수 N (2<= N <= 10)이 주어진다
- 1부터 N까지 각각 갖는 인구의 값이 주어진다
- 1부터 N까지 인접해있는 구역의 정보가 주어진다 (인접행렬)
- 선거구는 2개로 나눈다
- 팀을 만들었을 때 해당 선거구는 서로 연결되어 있어야 한다
- 연결되어있지 않다면 선거구가 될 수 없다
- 두 선거구로 나누었을 때 만들 수 있는 최소 인구 차를 구한다
* 알고리즘
- 팀을 조합해야한다: DFS
- 조합된 팀이 연결되어있는지 확인: BFS
* 로직(Logic)
- 주어진 정보를 활용해 인접행렬로 만든다
- 팀을 조합한다
- 선거구 A를 0으로 설정
- 선거구 B를 1로 설정
- 조합을 한 뒤 각 팀별로 연결이 되어있는지 판단한다
- 해당 팀의 출발지만 찾고 큐에 넣는다
- 큐를 기반으로 인접한 곳을 마킹한다
- 선거구는 같지만 마킹이 안되어있다면 모순이기 때문에 false 리턴
- 두 팀 모두 연결이 제대로 연결되어 있다면 최소 인구 차를 계속해서 덮어나간다
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
class Location {
public int people; //인구
public Location(int people) {
this.people = people;
}
}
public class Problem_17471 {
static int N; //구역의 개수
static Location[] locations;
static int[][] matrix; //인접행렬
static int[] team;
static boolean[] checked;
static int answer = Integer.MAX_VALUE;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
N = Integer.parseInt(br.readLine());
locations = new Location[N+1]; //1~N까지
matrix = new int[N+1][N+1];
team = new int[N+1];
String input_people = br.readLine();
st = new StringTokenizer(input_people, " ");
int size = st.countTokens();
for(int i=1; i<=size; ++i){
locations[i] = new Location(Integer.parseInt(st.nextToken()));
}
for(int i=1; i<=N; ++i){
String input = br.readLine();
st = new StringTokenizer(input, " ");
int adjNum = Integer.parseInt(st.nextToken()); //인접한 곳의 개수
for(int a=0; a<adjNum; ++a){
int node = Integer.parseInt(st.nextToken());
matrix[i][node] = 1;
matrix[node][i] = 1;
}
}
//팀이 만들어지면 -> 해당 팀들이 링크에 속한지 아닌지 판단 -> 속한다면 최솟값으로 덮어주기
int index = 1;
makeTeam(index);
if(answer == Integer.MAX_VALUE) System.out.println(-1);
else System.out.println(answer);
}
private static void makeTeam(int index) {
if(index == N+1){
//각 팀들(A, B)이 연결되어있는지 판단
if(isLinked(0) && isLinked(1)){
//다 속한다면 최솟값 덮어주기
int people = getTeamPeople(); //각 팀의 인구 차이
answer = Math.min(answer, people);
}
return;
}
//0이면 A팀, 1이면 B팀
team[index] = 0;
makeTeam(index+1);
team[index] = 1;
makeTeam(index+1);
}
private static int getTeamPeople() {
int peopleA = 0;
int peopleB = 0;
for(int i=1; i<=N; ++i){
if(team[i] == 0) peopleA += locations[i].people;
else if(team[i] == 1) peopleB += locations[i].people;
}
return Math.abs(peopleA - peopleB);
}
private static boolean isLinked(int teamIdx) {
checked = new boolean[N+1];
Queue<Integer> queue = new LinkedList<>();
for(int i=1; i<=N; ++i){
//같은 팀들을
if(team[i] == teamIdx){
queue.offer(i);
checked[i] = true;
break;
}
}
//인접한 부분을 마킹시켜줌
while (!queue.isEmpty()){
int q = queue.poll();
for(int a=1; a<=N; ++a){
if(!checked[a] && team[a] == teamIdx && matrix[q][a] == 1) {
queue.offer(a);
checked[a] = true;
}
}
}
//같은 팀은 맞는데 마킹(check)이 안되어있다면 모순
for(int i=1; i<=N; ++i){
if(team[i] == teamIdx && !checked[i]){
return false;
}
}
return true;
}
}
'Algorithm > Problem_SW' 카테고리의 다른 글
모의 SW 역량테스트 (등산로 조정, 디저트 카페) (0) | 2020.02.04 |
---|---|
SW 역량 테스트 A형 기출 문제 (배열 돌리기 4) (0) | 2019.11.15 |
SW 역량 테스트 기출 문제(원판 돌리기) (0) | 2019.11.12 |
SW 역량 테스트 기출 문제(아기상어) (1) | 2019.10.18 |
SW 역량 테스트 기출 문제(미세먼지 안녕) (0) | 2019.10.16 |