一棵有点权的树,选择一些点,

使得每个点至少满足下列中的一个: 1.已被选择 2.父亲被选择 3.子节点至少有一个被选择

求点权和最小值

 

f[x][0]=SUM{ min(f[y][1],f[y][2] }

 f[x][2] = SUM { min(f[y][0],f[y][1],f[y][2]) } +a[I]

f[x][1] = min{ s-min(f[y][1],f[y][2]) + f[y][2] },s=sum{min(f[y][1],f[y][2] }  // 先假设子节点一个不选,求出s ,现在选择y ,即取 f[y][2], 

从s里去掉y的min() 值,改为f[y][2]

 


#include <bits/stdc++.h>
using namespace std ;
 const int N=1999;
 
 int a[N],in[N],f[N][3];
 int all,go[N],nxt[N],hd[N],n;
 
  void add(int x,int y){ 
     go[++all]=y,nxt[all]=hd[x],hd[x]=all;
 }
 void dfs(int x){
     int i,s=0;
     f[x][2]=a[x];
     for(i=hd[x];i;i=nxt[i]){
        int y=go[i]; dfs(y);
       
       f[x][0]+=min(f[y][1],f[y][2]);
       f[x][2]+=min(f[y][0],min(f[y][1],f[y][2]));
       s+=min(f[y][1],f[y][2]); 
    }
    f[x][1]=1e9;
    for(i=hd[x];i;i=nxt[i]){
        int y=go[i]; 
        f[x][1]=min(f[x][1],s-min(f[y][1],f[y][2])+f[y][2]);
    }
 }
 int main(){
     int rt,i,x,y,T;
     cin>>n;
     
     for(i=1;i<=n;i++){
           cin>>x; cin>>a[x]>>T;
      while(T--) 
        cin>>y,in[y]++,add(x,y);    
    }
    for(rt=1;in[rt];) rt++;
    
    dfs(rt);
    cout<<min(f[rt][1],f[rt][2]);
 }

 

posted on 2022-11-03 21:27  towboat  阅读(17)  评论(0)    收藏  举报