[프로그래머스] PS/Java

[lv3] 등대

SH3542 2024. 12. 4. 17:01

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

 



트리 그래프에서의 최소 지배 집합(minimum vertex cover)을 구하는 문제라고 한다. dfs + dp를 통해 구현했다.

 

 

1. dp 점화식 세우기

 

dp[node][1] = 현재 node가 on인 경우 최솟값

= sum(child node가 root고 off인 모든 서브트리의 최솟값)

= sum(dp[child][0])

 

dp[node][0] = 현재 node가 off인 경우 최솟값

= sum( min(child node가 root고 off인 서브트리의 최솟값 , child node가 root고 on인 서브트리의 최솟값 ) ) + 현재 node를 on하는 값

= sum( min(dp[child][0] , dp[child][1]) ) + 1

 

2. dfs

 

노드 중 아무거나 root로 잡고 bottom-up 방식으로 리프노드부터 갱신한다.

최종적으로 전체 트리를 이루는 최솟값을 구하고, on/off인 경우 중 min을 반환한다.

 

 

import java.util.*;

class Solution {
    int[][] dp;
    List<Integer>[] adj;

    // DFS로 트리를 탐색하며 최소 지배 집합 계산
    void solve(int node, int parent) {

        dp[node][0] = 0; // node를 끄는 값
        dp[node][1] = 1; // node를 켜는 값

        for (int neighbor : adj[node]) {
            // 부모 노드는 집계에서 제외
            if (neighbor == parent) continue;

            solve(neighbor, node); // 자식 노드 탐색

            // node를 끈다면, 자식은 반드시 켜져야 함
            dp[node][0] += dp[neighbor][1];

            // node를 켠다면, 자식은 켜거나 꺼질 수 있음
            dp[node][1] += Math.min(dp[neighbor][0], dp[neighbor][1]);
        }
    }

    public int solution(int n, int[][] lighthouse) {
        dp = new int[n + 1][2];
        adj = new ArrayList[n + 1];

        for (int i = 1; i <= n; i++) {
            adj[i] = new ArrayList<>();
        }

        for (int[] edge : lighthouse) {
            adj[edge[0]].add(edge[1]);
            adj[edge[1]].add(edge[0]);
        }

        solve(1, -1); // 1을 root로 시작 (아무 노드나 가능)

        return Math.min(dp[1][0], dp[1][1]);
    }
}

'[프로그래머스] PS > Java' 카테고리의 다른 글

[lv2] 압축  (1) 2024.12.06
[lv2] n진수 게임  (1) 2024.12.06
[lv3] 합승 택시 요금  (0) 2024.11.30
[lv2] 땅따먹기  (0) 2024.11.23
[lv2] 롤케이크 자르기  (0) 2024.11.19