<题目链接>

题目大意:
鲍勃喜欢玩电脑游戏,特别是战略游戏,但有时他无法找到解决方案,速度不够快,那么他很伤心。现在,他有以下的问题。他必须捍卫一个中世纪的城市,形成了树的道路。他把战士的最低数量的节点上,使他们可以观察所有的边。你能帮助他吗?士兵,鲍勃把一个给定的树,你的程序应该发现的最小数目。

解题分析:

最小点覆盖模板题,用最少的点来覆盖所有的边。建立无向图,然后求出其最大匹配,最小点覆盖数=最大匹配数。需要注意的是,本题用邻接矩阵存图跑匈牙利会T,所以用链式前向星存图。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int N = 1500+10;
 7 int match[N],vis[N],head[N];
 8 int n,vN,vM,cnt;
 9 struct Edge{
10     int to,next;
11 }edge[N*N];   
12 void addedge(int u,int v){
13     edge[++cnt].to=v,edge[cnt].next=head[u];
14     head[u]=cnt;
15 }
16 bool dfs(int u){
17     for(int i=head[u];~i;i=edge[i].next){    //这层循环就是遍历能够与u匹配的节点
18         int v=edge[i].to;
19         if(!vis[v]){
20             vis[v]=1;
21             if(match[v]==-1||dfs(match[v])){
22                 match[v]=u;
23                 return true;
24             }
25         }
26     }
27     return false;
28 }
29 int Hungary(){
30     int ans=0;
31     memset(match,-1,sizeof(match));
32     for(int i=0;i<vN;i++){
33         memset(vis,0,sizeof(vis));
34         if(dfs(i))ans++;
35     }
36     return ans;
37 }
38 int main(){
39     while(scanf("%d",&n)!=EOF){
40         cnt=0;memset(head,-1,sizeof(head));
41         for(int i=1;i<=n;i++){
42             int u,v,k;scanf("%d:(%d)",&u,&k);
43             while(k--){
44                 scanf("%d",&v);
45                 addedge(u,v),addedge(v,u);   //存双向边
46             }
47         }
48         vN=vM=n;
49         int ans=Hungary();
50         printf("%d\n",ans/2);   //最小点覆盖数=最大匹配数
51     }
52 }

 

 

2018-11-15