原题链接:http://poj.org/problem?id=3041
题目来源:http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=16967#problem/E
算法:匈牙利算法(二分匹配,求最小点覆盖数)
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()); } }