皇宫看守
题意:给一颗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; }