题目大意:给你一个N*N的矩阵,有一些格子里有小行星,现在Bessie有一些威力很大的炮弹,每一次射击都能够消灭掉矩阵中一行或一列的小行星,但是炮弹很贵,问你需要消灭掉所有小行星所需的最小炮弹数目。
思路:最小点覆盖的问题,将矩阵中每一个行看成集合A中的一个点,每一列看成集合B中的点如果第i行第j列有小行星则将Ai和Bj连一条边。题目要求的就是次二分图的最小点覆盖问题,在二分图中,最小点覆盖=最大匹配,可以使用匈牙利算法解决。
#include <iostream>
using namespace std;
const int SIZE = 520;
#include <stdio.h>
#include <memory.h>
int data[SIZE][SIZE];
int matched[SIZE];
int used[SIZE];
int n,k;
int dfs(int m) {
int i;
for ( i=1;i<=n;i++ ) {
if ( used[i]==0&&data[m][i]==1 ) {
used[i]=1;
if ( matched[i]==-1||dfs(matched[i]) ) {
matched[i]=m;
return 1;
}
}
}
return 0;
}
/*求二分图的最小覆盖=最大二分匹配。最小覆盖:用最少的点(左右两边的点),让每条边都至少和其中一个点相关联。可以证明:最少的点(即覆盖数)=最大匹配数,最大匹配用匈牙利算法。matched数组记录right集中匹配的点的编号*/
int Hungary() {
int i,ctr;
ctr=0;
for ( i=1;i<=n;i++ ) {
memset(used,0,sizeof(used));
if ( dfs(i) )
ctr++;
}
return ctr;
}
int main()
{
int i,result;
int x,y;
while ( scanf("%d%d",&n,&k)!=EOF ) {
memset(data,0,sizeof(data));
memset(matched,-1,sizeof(matched));
for ( i=0;i<k;i++ ) {
scanf("%d%d",&x,&y);
data[x][y]=1;
}
result=Hungary();
printf("%d\n",result);
}
return 0;
}