题意:有一棵树,每个节点都有一个放置守卫的费用。若在某个节点放置守卫则与该节点相连的所有节点都能被看到。问能看到所有节点的最小费用是多少。
分析:树形dp
f[i]表示节点i防守卫的最小费用。
g[i]表示节点i不放守卫且被看到的最小费用。
h[i]表示节点i不被看到但所有子节点都被看到的最小费用。
f[i]=sum(min(f[soni],g[soni],h[soni]))
g[i]=sum(min(f[soni],g[soni]))若没有一个子节点是放置守卫则让增量最小的子节点防止守卫。
h[i]=sum(g[soni])
最后输出min(g[root],f[toot])
代码:
var n,x,y,z,i,j,root:longint; v:array[1..1500] of boolean; g,h,f,d:array[1..1500] of longint; a:array[1..1500,0..1500] of longint; function min(x,y:longint):longint; begin if x<y then exit(x) else exit(y); end; procedure dp(x:longint); var i,w:longint; flag:boolean; begin flag:=true; f[x]:=d[x]; for i:=1 to a[x,0] do begin dp(a[x,i]); f[x]:=f[x]+min(f[a[x,i]],min(g[a[x,i]],h[a[x,i]])); if f[a[x,i]]<=g[a[x,i]] then begin g[x]:=g[x]+f[a[x,i]]; flag:=false; end else g[x]:=g[x]+g[a[x,i]]; h[x]:=h[x]+g[a[x,i]]; end; if flag then begin w:=maxlongint div 1500; for i:=1 to a[x,0] do w:=min(w,f[a[x,i]]-g[a[x,i]]); g[x]:=g[x]+w; end; end; begin readln(n); fillchar(v,sizeof(v),true); for i:=1 to n do begin read(x,y); d[x]:=y; read(y); for j:=1 to y do begin read(z); inc(a[x,0]); a[x,a[x,0]]:=z; v[z]:=false; end; end; for i:=1 to n do if v[i] then begin root:=i; break; end; dp(root); writeln(min(f[root],g[root])); end.