树形DP——P2458 [SDOI2006]保安站岗

树形DP——P2458 [SDOI2006]保安站岗

这道题是用花费最少的费用来覆盖全部的点。这类问题的初始化可能有点麻烦。并且这个题目和一个点u以及这个点的父亲儿子有关。所以我们可以通过设置dp[u][0/1/2] 来分别表示当u这个点是用自己或者父亲或者儿子来覆盖u的。当时如果要考虑这个问题的时候说明u这个点的子树全部都覆盖好了。从这个方面来考虑如何进行动态规划。

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = 1500+10;
int cost[maxn];
int dp[maxn][3];
struct Edge{
    int v, next;
}edge[maxn<<1];
int head[maxn];
int cnt;
void addEdge(int u, int v)
{
    edge[cnt].next = head[u];
    edge[cnt].v = v;
    head[u] = cnt++;
    return;
}


void ini(int n)
{
    for(int i = 1; i <= n; i++)
        head[i] = -1;
    cnt = 0;
}

void dfs(int u, int fa)
{
    int flag = 0, flag1 = 0, Min2 = 0x3f3f3f3f;
    for(int i = head[u]; ~i; i = edge[i].next)
    {
        int v = edge[i].v;
        if(fa == v) continue;
        dfs(v, u);
        flag1 = 1;
        int Min;
        if(dp[v][0] < dp[v][1])
        {
            flag = 1;
            Min = dp[v][0];                 
        }
        else
        {
            Min = dp[v][1];
            Min2 = min(Min2, dp[v][0]-dp[v][1]);
        }  
        dp[u][1] += Min;
        dp[u][2] += Min;
        if(dp[v][2] < Min) Min = dp[v][2];
        dp[u][0]+= Min;
    }
    dp[u][0] += cost[u];
    if(!flag1) dp[u][1] = 0x3f3f3f3f;
    else if(!flag) dp[u][1] += Min2;
    return;
}
int main()
{
    int n;
    cin >> n ;
    ini(n);
    for(int i = 1; i <= n; i++)
    {
        int u, v, w, num;
        scanf("%d %d %d", &u, &w, &num);
        cost[u] = w;
        for(int z = 1; z <= num; z++)
        {
            scanf("%d", &v);
            addEdge(u, v);
            addEdge(v, u);
        }
    }
    dfs(1, 0);
    cout << min(dp[1][0], dp[1][1]);
    return 0;
 } 

 

posted @ 2021-03-18 19:50  斌斌翻水水  阅读(44)  评论(0)    收藏  举报