programmers

[프로그래머스]연습>>등대

윤만석 2023. 5. 9. 19:49

문제 설명

인천 앞바다에는 1부터 n까지 서로 다른 번호가 매겨진 등대 n개가 존재합니다. 등대와 등대 사이를 오가는 뱃길이 n-1개 존재하여, 어느 등대에서 출발해도 다른 모든 등대까지 이동할 수 있습니다. 등대 관리자 윤성이는 전력을 아끼기 위하여, 이 중 몇 개의 등대만 켜 두려고 합니다. 하지만 등대를 아무렇게나 꺼버리면, 뱃길을 오가는 배들이 위험할 수 있습니다. 한 뱃길의 양쪽 끝 등대 중 적어도 하나는 켜져 있도록 등대를 켜 두어야 합니다.

예를 들어, 아래 그림과 같이 등대 8개와 7개의 뱃길들이 있다고 합시다. 이 경우 1번 등대와 5번 등대 두 개만 켜 두어도 모든 뱃길은 양쪽 끝 등대 중 하나가 켜져 있으므로, 배들은 안전하게 운항할 수 있습니다.

등대의 개수 n과 각 뱃길이 연결된 등대의 번호를 담은 이차원 배열 lighthouse가 매개변수로 주어집니다. 윤성이가 켜 두어야 하는 등대 개수의 최솟값을 return 하도록 solution 함수를 작성해주세요.

트리에서 dp문제입니다.

dp배열을 2차원으로 생성합니다.

#include<bits/stdc++.h>
#define FAST ios_base::sync_with_stdio(false),cin.tie(NULL);
#define mset(v) memset(v,0,sizeof(v));
#define rep(i,a) for(int i=0;i<a;++i)
#define REP(i,a) for(int i=1;i<=a;++i)

using namespace std;

typedef long long ll;
typedef pair<int, int> pi;
typedef tuple<int, int, int>ti;
typedef vector<int> vi;
typedef vector<vector<int>> vvi;
int dy[] = { -1,0,1,0 }, dx[] = { 0,1,0,-1 }, INF = 987654321;

vi adj[100001],ch[100001];
int dp[100001][2];
int v[100001];
void dfs(int n){
    v[n]=1;
    if(adj[n].size()==1 && n!=1){
        //리프노드
        dp[n][1]=1;
        return;
    }
    for(int r:adj[n]){
        if(!v[r]){
            ch[n].push_back(r);
            dfs(r);
        }
    }
    dp[n][1]++;
    for(int r:ch[n]){
        dp[n][1]+=min(dp[r][0],dp[r][1]);
        dp[n][0]+=dp[r][1];
    }
}
int solution(int n, vector<vector<int>> lighthouse) {
    for(vi a:lighthouse){
        adj[a[0]].push_back(a[1]);
        adj[a[1]].push_back(a[0]);
    }
    dfs(1);
    return min(dp[1][0],dp[1][1]);
}