题意:
给你一颗有向树,每个士兵可以看守与他所在点相连的边,现在要你找出最少的点,使得所有的边都被覆盖。
题解:
在做这道题之前了解一下概念:
顶点覆盖:
在顶点集合中,选取一部分顶点,这些顶点能够把所有的边都覆盖了。这些点就是顶点覆盖集。
最小顶点覆盖:
在所有的顶点覆盖集中,顶点数最小的那个叫最小顶点集合。 最小点覆盖=最大匹配数
因为题目要我们求找出最小的点可以把所有边都覆盖,那么我们就可以根据最小点覆盖的概念去做这道题了,但是这道题我W了一发,为什么呢?因为我是存放的单向边,这样就会导致在匈牙利算法中有一些边是不连通的,不相信的话你用单边存放一下下面这组数据试试:
5
3:(1) 1
1:(1) 0
2:(1) 3
0:(0)
4:(1) 3
你就会发现了问题的,那么怎么改呢?改成双向的就可以了。
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXN=1500+7;
vector<int>map[MAXN];
bool vis[MAXN];
int cx[MAXN],cy[MAXN];
int n,m;
int dfs(int u)
{
for(int i=0;i<map[u].size();i++)
{
int v=map[u][i];
if(!vis[v])
{
vis[v]=true;
if(cy[v]==-1||dfs(cy[v]))
{
cx[u]=v;
cy[v]=u;
return 1;
}
}
}
return 0;
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)
map[i].clear();
for(int i=0;i<n;i++)
{
int u,v;
scanf("%d:(%d)",&u,&m);
for(int j=0;j<m;j++)
{
scanf("%d",&v);
map[u].push_back(v);
map[v].push_back(u);
}
}
memset(cx,-1,sizeof(cx));
memset(cy,-1,sizeof(cy));
int res=0;
for(int i=0;i<n;i++)
{
memset(vis,false,sizeof(vis));
res+=dfs(i);
}
printf("%d\n",res/2);
}
}