皇宫看守

题意:给一颗n个节点的树,每个节点有权值。从中选任意个节点,使得树上的每一个节点都被选中或与被选中的点直接相连,求选中节点的最小权值和

 

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;

inline int read()
{
    int f=1,x=0;
    char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}


int n,cnt;
int val[1505],v[1505],head[1505],nxt[1505];
int f[1505][3];
bool book[1505];

void add(int x,int y)
{
    v[++cnt]=y;
    nxt[cnt]=head[x];
    head[x]=cnt;
}

void dfs(int x)
{
    int i;
    int d=0x7fffffff;
    for(i=head[x];i;i=nxt[i])
    {
        int t=v[i];
        dfs(t);
        f[x][0]+=min(f[t][1],f[t][2]);//状态1 父亲选中 
        f[x][1]+=min(f[t][1],f[t][2]);//状态2 儿子选中 
        f[x][2]+=min(f[t][0],min(f[t][1],f[t][2]));//状态3 当前选中 
        d=min(d,f[t][2]-min(f[t][1],f[t][2]));//依靠儿子的节点,至少有一个儿子要选中自己 
    }
    f[x][2]+=val[x];
    f[x][1]+=d;
}

int main()
{
    int x,y,z;
    int i,j;
    n=read();
    for(i=1;i<=n;i++)
    {
        x=read();
        val[x]=read();
        y=read();
        while(y--)
        {
            z=read();
            book[z]=1;
            add(x,z);
        }
    }
    int root=0;
    for(i=1;i<=n;i++)
    {
        if(!book[i])
        {
            root=i;
            break;
        }
    }
    dfs(root);
    printf("%d",min(f[root][1],f[root][2]));
    return 0;
}

 

posted @ 2018-12-05 16:49  白驹过隙----青春绿  Views(230)  Comments(0Edit  收藏  举报