题意:在一棵树中,每个节点能监管连接自身的一条边,问最小选取几个节点能监管树中所有的边
思路:
1.一个节点可分为两种状态-选取或不选取
2.若当前结点选取了,那么子节点可以选择不选取;若当前结点未选取,那么子节点一定要选取;
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<map>
using namespace std;
const int N=2000;
struct E{
int val;
int next;
}edge[2*N+10];
int head[2*N],vis[2*N],c,dp[2*N][2];
int selMin(int x,int y)
{
return x<=y?x:y;
}
void add(int x,int y)
{
edge[c].val=y;
edge[c].next=head[x];
head[x]=c;
c+=1;
}
void DFS(int root)
{
dp[root][0]=0; //0状态表示该节点未选取
dp[root][1]=1; //1状态表示该节点被选取
vis[root]=1;
for(int i=head[root];i!=-1;i=edge[i].next)
{
int cur=edge[i].val;
if(!vis[cur])
{
DFS(cur);
dp[root][0]+=dp[cur][1];
dp[root][1]+=selMin(dp[cur][0],dp[cur][1]);
}
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
memset(dp,0,sizeof(dp));
int root;
c=0;
for(int i=1;i<=n;i+=1)
{
int p,k,x;
scanf("%d:(%d)",&p,&k);
if(i==1)
root=p;
while(k--)
{
scanf("%d",&x);
add(p,x);
add(x,p);
}
}
DFS(root);
printf("%d\n",selMin(dp[root][0],dp[root][1]));
}
return 0;
}