<알고리즘> Java, 매출 하락 최소화 - Tree(트리), DP

2026. 2. 27. 18:45·개인공부정리페이지

https://school.programmers.co.kr/learn/courses/30/lessons/72416

 

프로그래머스

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

programmers.co.kr

0. 문제 핵심 개념

 

DP(Dynamic Programming) : 동적 계획

DFS(Depth First Search) : stack 활용 끝짱보는 서치

 

단순 완전탐색이 아니라 탐색하면서 중복 계산을 줄여라는 뜻!

= “이미 계산한 결과는 저장해두고 다시 쓰자"

= DFS(자식 먼저 계산) → 그 결과를 이용해 부모 계산

 

 

DFS하면서, 이미 방문한 노드를 다시계산하는걸 방지한다. (시간 아끼려고!)

DFS + Memoization = DFS로 탐색하되 결과를 DP 배열에 저장해둔다.

 

이 문제에서 DP는 아래와 같이 사용한다.

dp[vertex][0] = vertex가 워크샵에 참여하지 않을경우 매출 손실 비용
dp[vertex][1] = vertex가 워크샵에 참여할 경우 매출 손실 비용

 

이때, 팀별로 고려해줘야하므로 가장 최하단의 리프노드부터 진행해주면된다.


 

1. vertex(자기자신)이 참석한 경우

 

이를위해 input받은 list배열의 링크를 팀별로 고려해주기위해 정렬했다.

` Arrays.sort(links, a[0]-b[0]);`

 

팀원 각각이 맡고 있는 매출액의 경우의 수 두가지  중 가장 적은 매출액을 맡고 있을 경우를 팀원별로 전부 더해줍니다.

  1.  팀원이 참여하지 않은 경우 (not me)
  2. 팀원이 참여한 경우 (not me)

즉, 본인제외 모든 팀원들의 합산  `teamSum += min( dp[vertex][0], dp[vertex][1])` 

본인 팀의 모든 팀원에 대해 수행

 

거기에,, `teamSum += sales[me][1]` // 자기자신의 참여값 더해준다.

 

팀장이 팀원들의 매출액의 합산을 넘겨받고, 1번 vertex 까지 넘긴다. (1 == CEO)

`min(DP[1][0], DP[1][1]) + sales[me][1] `이 최종 값이된다. 


 

정리! :

`DP[me][1] = sales[x] + sum(min(DP[child][0], DP[child][1]))`

(자식 vertex들의 cost 최솟값 + 자기자신)

  • 내가 참석하면
  • 내 팀원들은 참석 여부 무관함. (해도되고 안해도되고) -> 최소비용을 선택해준다!!!!

2. vertex(자기 자신)이 참석하지 않은경우

-> 2.1 &2.2 두가지 case 로 나뉜다.

2.1. 팀원 한명이 참석하는 게 더 비용이 적은 경우

팀원 중에 적어도 한명이 워크숍에 참석함.

이 경우는 팀장이 워크샵에 참석하지 않는 경우를 의미함. (왜? 자기자신을 팀장이라고 가정해야함.)

 

위에서는 DP[me][1]을 구했지만, 여기에서는 DP[me][0]을 구한다.

 

 DP[child][1] <= DP[child][0] // 팀원 자신이 참여한경우가 최소 매출액이 존재함.


정리! :

`DP[me][0] = sum(min(DP[child][0], DP[child][1]))`

(단,  DP[child][1] <= DP[child][0]이 되는 vertex가 존재하는 경우만)

  • 내가 불참
  • 내 직속부하(팀원) 최소 1명 이상 반드시 참석

 


2.2 팀원 중에서 한 명도 참석하지 않은 경우. (전부 불참하는게 비용 적음)

DP[정점][0]를 구하는 두 번째 경우이다. 그럼 적어도 한명 이상의 자식이 워크숍에 참석해야겠죠?

위에서 DP[child][1] <= DP[child][0] 라는 조건이 붙었었다. 이게 존재하지 않는다는 의미이다.

다만 이 경우에는 팀원들의 최소매출액 계산 시, 전부 다 DP[k][0]이 최소가 되는 값밖에 존재하지 않음.

그럼 조건 위반 🚨

-> 팀원들이 참석하는 경우를 억지로 만들어야함.

 

손해를 최소화해야 하니까.... min( DP[child][1] - DP[child][0] )!

팀장이 참석하지않으면, 팀장이 맡아야하는 매출액 최소값 == min(팀원1,팀원2, ... 팀원n)  이 되어야함

근데 전부다 DP[child][0]의 값에 해당함. 누군가는 DP[child][1]로 만들어줘야한다.

==  -DP[child][0] + DP[child][1] 이 최소가 되는 값을 더해주어야 팀장이 맡을 매출액의 합산이 줄어듦을 알 수 있습니다.

각 팀원에 대해 min( DP[child][1]  - DP[child][0] )을 기존 최소합산값에 더해줌.

 

이 경우, 팀원이 참석X 경우가 항상 최솟값이므로 항상  DP[child][1]  -DP[child][0] > 0이다.


 

`DP[me][0] = sum(min(DP[child][0], DP[child][1])) + min(DP[child][1] - DP[k][0])`

팀원들의 vertex인, child에 대해 전부 순회한다. 단, DP[child][1]  -DP[child][0] > 0인 경우만!)

 


3. 전체 알고리즘 정리 (DFS + DP)

 

DFS(v) {
	dp[v][1] = sales[v];
    dp[v][0] = 0; 
    temp = Integer.MAX_BALUE;
    flag = false;
    
    for(child : children[v]){ //v의 자식노드들에 대해 진행
    	DFS(child);
        
        dp[v][1] += min(dp[child][0], dp[child][1]); // case 1: 본인참여 + 자식 참여 여부 최솟값
        dp[v][0] += min(dp[child][0], dp[child][1]); // 본인참여x
        
        // case2: 2.1, 본인 불참 + 자식 한명이 참여한다.
        if (dp[child][1] <= dp[child][0]){ 
        	flag = true; //한명이상 참여함.
        }
        
        // 2.2 본인불참 & 팀원 전원 불참이 값쌈. :: 한명을 불참 ->참석
        temp = min(temp, dp[child][1] - dp[child][0]); 
        }
        
    // 2.2 (본인참여X, 팀원 억지로 한명 참여시키기  
	if (flag == false) { //전원 불참
   		dp[v][0] += temp;
    }
}

 

 

자바에서 트리를 만들어보자. List를 활용한다

 

List<Integer>[] children = new ArrayList[n + 1];

 

이 표현방식의 의미 : 배열 안에 List가 들어있다. 대괄호 앞에부분 List<Integer>의 배열이라는 의미!!!

ArrayList타입의 배열을 만든다[n+1]크기의.

children
   |
   |-- [0] -> List<Integer>
   |-- [1] -> List<Integer>
   |-- [2] -> List<Integer>
   |-- [3] -> List<Integer>
   ...

 

주의!

배열은 실제 클래스기준으로 만들어짐 : 제네릭 타입 정보는 런타임에 사라진다. 그래서 컴파일단계에서 넘어가기위해서

제네릭 타입의 배열 생성이 금지된다.

ex)

❌ `List<Integer>[] arr = new ArrayList<Integer>[5];` 이런건 불가능하다.

✅  `List<Integer>[] arr = new ArrayList[5]; `  // 경고는 뜰 수 있음

그냥 ArrayList 배열 생성 <Integer> 안 붙었다. 그래서 허용

 

tree/graph 나올때 많이 사용하는 방식

List<Integer>[] arr = new ArrayList[5];

for (int i = 0; i < 5; i++) {
    arr[i] = new ArrayList<>();
}

정답 코드

import java.util.*;

class Solution {
    int[][] dp;
    int[] sales;
    int[][] links;
    List<Integer>[] children;
    public int solution(int[] sales, int[][] links) {
        // cost 저장할 배열
        this.sales = sales;
        dp = new int[sales.length+1][2]; 
        children = new ArrayList[sales.length+1];
        
        for(int i=0; i<= sales.length; i++){
            children[i] = new ArrayList<>(); // 미니 ArrayList들 생성
        }
        
        for(int[] link : links){ //트리구조 연결. 
            int parent = link[0];
            int child = link[1];
            children[parent].add(child);
        }
        
        dfs(1);
        
        return Math.min(dp[1][1], dp[1][0]);
        
    }
    

    public void dfs(int v){
        dp[v][1] = sales[v-1];
        dp[v][0] = 0;
        
        boolean flag = false;
        int temp = Integer.MAX_VALUE;
        
        for(int child : children[v]){
            dfs(child);
            
            int min = Math.min(dp[child][0], dp[child][1]);
            dp[v][1] += min;
            dp[v][0] += min;
            
            if(dp[child][1] <= dp[child][0]){
                flag = true;
            }
            temp = Math.min(temp, dp[child][1] - dp[child][0]);  
        }
        if(!flag && children[v].size() > 0){
            dp[v][0] += temp;
        }
    }
}

'개인공부정리페이지' 카테고리의 다른 글

<SQL 고득점 Kit> 01. SELECT  (0) 2026.02.28
<MySQL> DATETIME 타입 DATE로 변환  (0) 2026.02.26
[트러블슈팅].. PEM키가 공개된사건  (2) 2025.11.29
MergeSort implement in C  (0) 2025.09.24
코드 포매터  (0) 2025.08.31
'개인공부정리페이지' 카테고리의 다른 글
  • <SQL 고득점 Kit> 01. SELECT
  • <MySQL> DATETIME 타입 DATE로 변환
  • [트러블슈팅].. PEM키가 공개된사건
  • MergeSort implement in C
sihyes
sihyes
24학번 컴퓨터공학과
  • sihyes
    시혜적으로개발
    sihyes
  • 글쓰기 관리
  • 전체
    오늘
    어제
    • 분류 전체보기 (114)
      • 단순 설정 (10)
      • 백엔드 공부(BE, AWS) (8)
        • 로그인&회원가입 (3)
        • 파일업로드&GPT (2)
      • 컴퓨터공학과 (51)
        • 운영체제 (0)
        • Artificial Intelligence (0)
        • Java 1 & 2 (23)
        • 컴퓨터네트워크 (3)
        • 모앱JavaScript (0)
        • Data structures (9)
        • 소프트웨어공학 (5)
        • 오픈SW플랫폼 제출용 (5)
        • Python - 문해프 (1)
      • 개인 프로젝트 (2)
        • 알바솔로몬 (1)
        • PLACO 프로젝트 (0)
      • 도서 공부(정리) (20)
        • 알고리즘 코딩 테스트 자바 편 (1)
        • SQL첫걸음 (8)
        • 코딩 자율학습 스프링 부트 3 자바 백엔드 개발 .. (6)
        • Do it! 지옥에서 온 문서 관리자 깃&깃허브 .. (5)
      • 개인공부정리페이지 (12)
        • 백준 & 프로그래머스 (3)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    ㅇ
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.4
sihyes
<알고리즘> Java, 매출 하락 최소화 - Tree(트리), DP
상단으로

티스토리툴바