KimMinJun
Coding Note
KimMinJun
전체 방문자
오늘
어제
  • 분류 전체보기 (486)
    • ALGORITHM (11)
      • 정렬 (6)
      • 최단경로 (1)
      • 자료구조 (1)
      • 슬라이딩 윈도우 (1)
      • etc (2)
    • Git (5)
    • Web (24)
      • Vanilla JS (13)
      • TS (2)
      • React (7)
      • ETC (1)
    • React 공식문서 (번역, 공부) (11)
      • Quick Start (2)
      • Installation (0)
      • Describing the UI (9)
      • Adding Interactivity (0)
      • Managing State (0)
      • Escape Hatches (0)
    • Next.js 공식문서 (번역, 공부) (3)
      • Getting Started (2)
      • Building Your Application (1)
    • PS (431)
      • 백준 (187)
      • Programmers (104)
      • CodeUp (21)
      • STL (3)
      • 제코베 JS 100제 (50)
      • SWEA (0)
      • LeetCode (65)
    • IT (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • 관리

공지사항

인기 글

태그

  • Level1
  • 수학
  • C++
  • 백준
  • 제코베 JS 100제
  • Level 2
  • tree
  • 정렬
  • js
  • codeup
  • 문자열
  • recursion
  • 다이나믹 프로그래밍
  • C
  • Level 0
  • LeetCode
  • 그래프
  • Level 1
  • programmers
  • string

최근 댓글

최근 글

hELLO · Designed By 정상우.
KimMinJun

Coding Note

PS/백준

백준 / 그래프 / 17471번 / 게리맨더링 / Java

2023. 9. 2. 22:09

< 문제 바로가기 >

 

17471번: 게리맨더링

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

www.acmicpc.net

 

package boj.p17471;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.LinkedList;
import java.util.StringTokenizer;

public class Main {
	private static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	private static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
	private static StringTokenizer st = null;
	
	/** 구역의 개수 */
	private static int N;
	/** 각 구역의 인구 */
	private static int[] populationList;
	/** 인접 리스트 */
	private static LinkedList<Integer>[] adjList;
	
	/** true와 false로 나뉜 두 구역 */
	private static boolean[] divide;
	
	/** 인구 차이의 최솟값 */
	private static int minDistance;

	public static void main(String[] args) throws Exception {
		input();
		solve();
		print();
	}

	private static void input() throws Exception {
		N = Integer.parseInt(br.readLine());
		
		populationList = new int[N + 1];
		st = new StringTokenizer(br.readLine());
		for(int i=1; i<=N; i++) {
			populationList[i] = Integer.parseInt(st.nextToken());
		}
		
		adjList = new LinkedList[N + 1];
		for(int i=1; i<=N; i++) {
			adjList[i] = new LinkedList<>();
		}
		for(int i=1; i<=N; i++) {
			st = new StringTokenizer(br.readLine());
			
			int n = Integer.parseInt(st.nextToken());
			for(int j=1; j<=n; j++) {
				adjList[i].add(Integer.parseInt(st.nextToken()));
			}
		}
		
		br.close();
	}
	
	private static void solve() {
		minDistance = Integer.MAX_VALUE;
		divide = new boolean[N + 1];
		
		getMinDistance(1);
	}
	
	private static void getMinDistance(int idx) {
		// 모든 구역을 끝까지 탐색하여 조합을 구성한 경우,
		if(idx == N + 1) {
			for(int i=1; i<=N; i++) {
				// true인 구역끼리 이어지는지 검사한다.
				if(divide[i] == true) {
					if(isConnected(i, true) == false) {
						return;
					}
					// 모두 이어져 있어야 하기 때문에 한번만 검사해도 된다.
					break;
				}
			}
			for(int i=1; i<=N; i++) {
				// false인 구역끼리 이어지는지 검사한다.
				if(divide[i] == false) {
					if(isConnected(i, false) == false) {
						return;
					}
					// 모두 이어져 있어야 하기 때문에 한번만 검사해도 된다.
					break;
				}
			}
			
			int area1 = 0; // true 구역의 인구수
			int area2 = 0; // false 구역의 인구수
			
			// 각 구역의 인구수를 세준다.
			for(int i=1; i<=N; i++) {
				if(divide[i] == true) {
					area1 += populationList[i];
				}
				else {
					area2 += populationList[i];
				}
			}
			
			int distance = Math.abs(area1 - area2);
			// 최소값 갱신한다.
			minDistance = Math.min(minDistance, distance);
			
			return;
		}
		
		for(int i=idx; i<=N; i++) {
			if(divide[i] == true) {
				continue;
			}
			
			divide[i] = true;
			getMinDistance(i + 1);
			divide[i] = false;
		}
	}
	
	/**
	 * 조합으로 구한 두 나뉘어진 선거구가 같은 선거구끼리 이어지는지 검사하는 함수
	 * 
	 * @param start 시작 구역
	 * @param flag 구역
	 * @return
	 */
	private static boolean isConnected(int start, boolean flag) {
		int flagCnt = 0;
		// 인자로 들어온 flag에 해당하는 선거구 내부의 구역의 개수를 세준다.
		for(int i=1; i<=N; i++) {
			if(divide[i] == flag) {
				flagCnt++;
			}
		}
		
		Deque<Integer> stack = new ArrayDeque<>();
		boolean[] isVisited = new boolean[N + 1];
		
		isVisited[start] = true;
		stack.push(start);
		
		while(!stack.isEmpty()) {
			int cur = stack.pop();
			flagCnt--;
			
			for(int next : adjList[cur]) {
				if(isVisited[next] == true) {
					continue;
				}
				if(divide[next] != flag) {
					continue;
				}
				
				isVisited[next] = true;
				stack.push(next);
			}
		}
		
		// 모두 이어져 있다면 true를 반환한다.
		return flagCnt == 0;
	}

	private static void print() throws Exception {
		// 두 선거구로 나눌 수 없는 경우에는 초기값 그대로 있으므로, -1로 바꿔준다.
		if(minDistance == Integer.MAX_VALUE) {
			minDistance = -1;
		}
		
		bw.write(minDistance + "");
		bw.flush();
		bw.close();
	}
}
저작자표시

'PS > 백준' 카테고리의 다른 글

백준 / 그래프 / 1189번 / 컴백홈 / JS  (0) 2023.12.05
백준 / 그리디 / 1744번 / 수 묶기 / Java  (0) 2023.11.07
백준 / 그래프 / 20058번 / 마법사 상어와 파이어스톰 / Java  (0) 2023.08.27
백준 / 백트래킹 / 15683번 / 감시 / Java  (0) 2023.07.27
    'PS/백준' 카테고리의 다른 글
    • 백준 / 그래프 / 1189번 / 컴백홈 / JS
    • 백준 / 그리디 / 1744번 / 수 묶기 / Java
    • 백준 / 그래프 / 20058번 / 마법사 상어와 파이어스톰 / Java
    • 백준 / 백트래킹 / 15683번 / 감시 / Java
    KimMinJun
    KimMinJun

    티스토리툴바