洛谷2458

f[now][0]表示以当前点为根,且要取该点,满足条件的最小

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
int head[1501],to[1501],nex[1501],val[1501],indg[1501],f[1501][3],n,cnt,rt;

inline void read(int &x){
    char ch=getchar();x=0;
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} 
}

void addedge(int u,int v){
    to[++cnt]=v;nex[cnt]=head[u];head[u]=cnt;
}

void dfs(int now){
    if(!head[now]){f[now][0]=f[now][1]=val[now];f[now][2]=0;return;}
    f[now][0]=val[now];f[now][2]=0;
    for(int i=head[now];i;i=nex[i]){
        dfs(to[i]);
        f[now][0]+=min(f[to[i]][1],min(f[to[i]][2],f[to[i]][0]));
        f[now][2]+=min(f[to[i]][0],f[to[i]][1]);}
    f[now][1]=1e9;
    for(int i=head[now];i;i=nex[i]){
        f[now][1]=min(f[now][1],f[now][2]-min(f[to[i]][0],f[to[i]][1])+f[to[i]][0]);
    }
}

int main(){
    read(n);
    for(int i=1;i<=n;i++){
        int u,som,v;read(u);read(val[u]);read(som);
        while(som--){read(v);indg[v]++;addedge(u,v);}
    }
    for(int i=1;i<=n;i++)if(!indg[i]){rt=i;break;}
    dfs(rt);
    printf("%d",min(f[rt][0],f[rt][1]));
}

 
f[now][1]表示以当前点为根,至少取它的一个儿子,满足条件的最小值
f[now][2]表示他的儿子均被覆盖,满足条件的最小值
f[now][0]=val[now]+segma(min(f[son][0~2]));
f[now][1]=min(f[now][2]-min(f[son][0~1])+f[son][0])
f[now][2]=segma(f[son][0~1])
再注意叶子节点的赋值即可

猜你喜欢

转载自www.cnblogs.com/MikuKnight/p/9021649.html