题意:给出一个N*N的矩阵,有的位置有行星。已知一枪可以击溃一行或一列上的所有行星。问最少多少枪可以击溃 所有的行星。
思路:以行作为X集合,以列作为Y集合,一个行星在(x,y),则x对应X中的点向y对应Y中的点连一条边,则某个顶点一 旦被选,则与之相连的边(也就是行星)都会被选,也就是选出最少的顶点覆盖所有的边,即最小顶点覆盖。
算法:
Konig定理:一个二分图中的最大匹配数等于这个图中的最小点覆盖数。
最小点覆盖数:假如选中了一个点就相当于覆盖了以它为端点的所有边,你需要选择最少的点覆盖所有的边。
PS:模板题目,直接套用匈牙利算法求最大的匹配数的模板即可。关键是理解如何建图。
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAX=1e3+10;
bool relationship[MAX][MAX];
bool vis[MAX];
int partner[MAX];
int k,m,n;
bool find(int f){
for(int i=1;i<=m;i++){
int v=i;
if(relationship[f][v]&&!vis[v]){
vis[v]=true;
if(partner[v]<0||find(partner[v])){
partner[v]=f;
return true;
}
}
}
return false;
}
int main(){
while(cin>>m>>n){
int x,y;
memset(partner,-1,sizeof(partner));
memset(relationship,false,sizeof(relationship));
for(int i=0;i<n;i++){
scanf("%d %d",&x,&y);
relationship[x][y]=true;
}
int ans=0;
for(int i=1;i<=m;i++){
memset(vis,false,sizeof(vis));
if(find(i))
ans++;
}
cout<<ans<<endl;
}
return 0;
}