프로그래머스 시험장 나누기 JAVA 풀이 (이분 탐색, DFS, 트리)

2026. 6. 10. 16:33·코테(Solved.ac + Programmers)
728x90

📌 문제 링크

 

프로그래머스

SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr


📌 문제 개요

여러 개의 시험장이 하나의 이진 트리 형태로 연결되어 있다.

각 시험장에는 응시자 수가 존재하며, 시험장 사이의 간선을 끊어 정확히 k개의 그룹으로 나누어야 한다.

 

각 그룹의 응시자 수 합을 계산했을 때,

가장 큰 그룹의 인원 수 를 최소화하는 것이 목표이다.

 

즉, 최대 그룹 인원 수의 최솟값 을 구하는 문제이다.


📌 접근 방법

처음에는 어떤 간선을 끊어야 하는지 직접 찾는 문제처럼 보인다.

하지만 시험장 수가 최대 10,000개이므로 모든 경우를 탐색하는 것은 불가능하다.

 

문제를 다시 보면, 최대 그룹 인원 수를 최소화 해야 한다.

 

이 문구를 보고 이분 탐색(Parametric Search)을 적용할 수 있다고 판단했다.

먼저 최대 그룹 인원 수를 limit라고 가정한다.

 

그 다음 DFS를 수행하면서 확인한다.

현재 limit 이하로 그룹을 나눌 수 있는가?
 

DFS 결과 필요한 그룹 수가

k 이하라면 더 작은 limit를 탐색하고,

k 초과라면 limit를 증가시키는 방식으로 정답을 찾는다.


📌 핵심 아이디어

1. 최대 그룹 인원 수를 이분 탐색한다

정답은 그룹 인원 수이므로 탐색 범위를 설정할 수 있다.

최소값은 단일 시험장 인원 중 최대값이다.

for (int n : num) {
    left = Math.max(left, n);
}

최대값은 모든 시험장의 응시자 수를 더한 값이다.

이 범위 안에서 최대 그룹 인원 수를 탐색한다.

for (int n : num) {
    right += n;
}

2. DFS로 필요한 그룹 수를 계산한다

현재 노드 기준으로 하나의 그룹으로 묶을 수 있는지 확인한다.

왼쪽 서브트리
오른쪽 서브트리
현재 노드

모두 포함 가능하다면 그룹을 유지한다.

if (left + right + num[cur] <= limit) {
    return left + right + num[cur];
}

예를 들어 아래와 같다면 하나의 그룹으로 유지할 수 있다.

현재 노드 = 5
왼쪽 합 = 10
오른쪽 합 = 15
limit = 40
10 + 15 + 5 = 30

3. 한쪽만 포함 가능한 경우

양쪽을 모두 포함할 수 없다면 더 작은 쪽만 유지한다.

if (Math.min(left, right) + num[cur] <= limit) {
    groupCount++;
    return Math.min(left, right) + num[cur];
}

예를 들어

  • 오른쪽만 포함 왼쪽은 분리하게 된다.
  • 이 경우 그룹 수가 1 증가한다.
현재 노드 = 5
왼쪽 합 = 30
오른쪽 합 = 10
limit = 20
 

4. 둘 다 포함할 수 없는 경우

현재 노드와 자식들을 모두 함께 유지할 수 없다면 양쪽을 모두 분리한다.

groupCount += 2;
return num[cur];

예를 들어 아래와 같다면, 양쪽 서브트리를 모두 분리해야 한다.

현재 노드 = 15
왼쪽 합 = 20
오른쪽 합 = 25
limit = 30

5. 루트 노드 직접 찾기

문제에서는 루트 노드가 주어지지 않는다.

따라서 자식으로 등장하지 않은 노드를 찾아야 한다.

boolean[] isChild = new boolean[num.length];

for (int[] link : links) {
    if (link[0] != -1) isChild[link[0]] = true;
    if (link[1] != -1) isChild[link[1]] = true;
}

자식으로 한 번도 등장하지 않은 노드가 루트가 된다.


📌 전체 코드

class Solution {

    int[] num;
    int[][] links;
    int k;
    int groupCount;

    public int solution(int k, int[] num, int[][] links) {
        this.num = num;
        this.links = links;
        this.k = k;

        int root = findRoot();

        int left = 0;
        int right = 0;

        for (int n : num) {
            left = Math.max(left, n);
            right += n;
        }

        int answer = right;

        while (left <= right) {
            int mid = (left + right) / 2;

            groupCount = 1;
            dfs(root, mid);

            if (groupCount <= k) {
                answer = mid;
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }

        return answer;
    }

    int dfs(int cur, int limit) {
        if (cur == -1) return 0;

        int left = dfs(links[cur][0], limit);
        int right = dfs(links[cur][1], limit);

        if (left + right + num[cur] <= limit) {
            return left + right + num[cur];
        }

        if (Math.min(left, right) + num[cur] <= limit) {
            groupCount++;
            return Math.min(left, right) + num[cur];
        }

        groupCount += 2;
        return num[cur];
    }

    int findRoot() {
        boolean[] isChild = new boolean[num.length];

        for (int[] link : links) {
            if (link[0] != -1) isChild[link[0]] = true;
            if (link[1] != -1) isChild[link[1]] = true;
        }

        for (int i = 0; i < num.length; i++) {
            if (!isChild[i]) return i;
        }

        return -1;
    }
}
 

📄 정리

  • 최대 그룹 인원 수의 최솟값을 구하는 문제이므로 이분 탐색을 적용할 수 있다.
  • DFS 후위 순회를 이용해 현재 limit에서 필요한 그룹 수를 계산한다.
  • 그룹 수가 k 이하이면 더 작은 limit를 탐색한다.
  • 루트 노드가 주어지지 않으므로 직접 찾아야 한다.
  • 트리 + DFS + Parametric Search가 결합된 카카오 고난도 문제
728x90

'코테(Solved.ac + Programmers)' 카테고리의 다른 글

프로그래머스 PCCP 기출문제 - 저수지 물 사용량 예측(Java)  (0) 2026.06.11
프로그래머스 옹알이 JAVA 풀이(문자열, 구현)  (0) 2026.06.10
프로그래머스 문자열 나누기 JAVA 풀이 (문자열, 구현)  (0) 2026.06.09
프로그래머스 비밀지도 JAVA 풀이 (비트연산, 문자열 변환)  (0) 2026.06.09
프로그래머스 모의고사 JAVA 풀이 (완전탐색)  (0) 2026.06.06
'코테(Solved.ac + Programmers)' 카테고리의 다른 글
  • 프로그래머스 PCCP 기출문제 - 저수지 물 사용량 예측(Java)
  • 프로그래머스 옹알이 JAVA 풀이(문자열, 구현)
  • 프로그래머스 문자열 나누기 JAVA 풀이 (문자열, 구현)
  • 프로그래머스 비밀지도 JAVA 풀이 (비트연산, 문자열 변환)
PUSH → MERGE → DEPLOY
PUSH → MERGE → DEPLOY
데이터 흐름과 운영 자동화를 설계하는 백엔드 개발자
  • PUSH → MERGE → DEPLOY
    Coding Dongin
    PUSH → MERGE → DEPLOY
  • 전체
    오늘
    어제
    • MEUN
      • 코테(Solved.ac + Programmers)
      • BootCamp(JAVA)
      • JAVA
      • SpringBoot
      • JavaScript
      • JSP
      • DB(SQL)
      • React
      • HTML_CSS
      • jQuery
      • SCSS
      • GSAP
      • 설치 + 꿀팁
      • 정보처리기사 오답노트
      • 정보처리기사 기출문제
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • GIT
  • 공지사항

  • 인기 글

  • 태그

    dp
    springboot
    백준
    실기
    Level2
    solved.ac
    level1
    피보나치
    수학
    정처기오답노트
    프로그래머스
    코딩테스트
    백엔드개발자
    정처기실기
    배열
    구현
    정보처리기사 실기 기출문제
    자료구조
    완전탐색
    기출문제
    문자열
    정처기
    자바
    정보처리기사
    정렬
    알고리즘
    java
    시뮬레이션
    level0
    브루트포스
  • 최근 댓글

  • 최근 글

  • 250x250
  • hELLO· Designed By정상우.v4.10.4
PUSH → MERGE → DEPLOY
프로그래머스 시험장 나누기 JAVA 풀이 (이분 탐색, DFS, 트리)
상단으로

티스토리툴바