洛咕
题意:在一棵树的结点上放置最少数目的士兵,使得这些士兵能瞭望到所有的路.注意,某个士兵在一个结点上时,与该结点相连的所有边将都可以被瞭望到.
分析:很经典的一道节点01型树上背包问题.对于每一个节点只有两种情况,选(1)或者不选(0).所以状态转移只有两种:
(f[u][0]+=f[v][1]),若父节点u不选,则子节点v都要选.
(f[u][1]+=min(f[v][0],f[v][1])),若父节点u被选了,则子节点v取最优情况.
初始化(f[u][1]=1,f[u][0]=0).
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
return s*w;
}
int n,root;
int visit[1505],f[1505][2];
vector<int> q[1505];
void dfs(int u){
f[u][1]=1;f[u][0]=0;
for(int i=0;i<q[u].size();i++){
int v=q[u][i];
dfs(v);
f[u][0]+=f[v][1];
f[u][1]+=min(f[v][0],f[v][1]);
}
return;
}
int main(){
n=read();
for(int i=1;i<=n;i++){
int num=read(),size=read();
for(int j=1;j<=size;j++){
int son=read();
q[num].push_back(son);
visit[son]=1;//标记是子节点
}//存边,根据个人习惯
}
for(int i=0;i<n;i++)//找根
if(!visit[i]){root=i;break;}
dfs(root);
printf("%d
",min(f[root][0],f[root][1]));
return 0;
}