原题链接:
题目来源:
算法:匈牙利算法(二分匹配,求最小点覆盖数)
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 10768 | Accepted: 5823 |
Description
Input
Output
Sample Input
3 4 1 1 1 3 2 2 3 2
Sample Output
2
Hint
Source
题意:给出一个N*N的矩阵,有的位置有行星。已知一枪可以击溃一行或一列上的所有行星。问最少多少枪可以击溃 所有的行星。
思路:以行作为X集合,以列作为Y集合,一个行星在(x,y),则x对应X中的点向y对应Y中的点连一条边,则某个顶点一 旦被选,则与之相连的边(也就是行星)都会被选,也就是选出最少的顶点覆盖所有的边,即最小顶点覆盖。
算法:
Konig定理:一个二分图中的最大匹配数等于这个图中的最小点覆盖数。
最小点覆盖数:假如选中了一个点就相当于覆盖了以它为端点的所有边,你需要选择最少的点覆盖所有的边。
PS:模板题目,直接套用匈牙利算法求最大的匹配数的模板即可。关键是理解如何建图。
#include<stdio.h>
#include<string.h>
const int maxn=510;
int g[maxn][maxn];
int linker[maxn];
bool used[maxn];
int n,m;
int uN,vN;
int find(int u)
{
int v;
for(v=1;v<=vN;v++)
{
if(!used[v] && g[u][v])
{
used[v]=true;
if(linker[v]==-1 || find(linker[v]))
{
linker[v]=u;
return true;
}
}
}
return false;
}
int hugary()
{
int u;
int sum=0;
memset(linker,-1,sizeof(linker));
for(u=1;u<=uN;u++)
{
memset(used,false,sizeof(used));
if(find(u)) sum++;
}
return sum;
}
int main()
{
int u,v;
while(scanf("%d%d",&n,&m)!=EOF)
{
uN=vN=n;
memset(g,0,sizeof(g));
while(m--)
{
scanf("%d%d",&u,&v);
g[u][v]=1;
}
printf("%d\n",hugary());
}
}