- 题目大意
在N*N的0和1组成的格子,一次操作可以将一行或一列的1全部变成0,问至少要进行多少次操作才能将所有的1全部变成0.
分析
这道题是一道比较基础的二分图匹配问题,但也需要一点思维。考虑每一个为1的格子,因为它是一定会被变成0的所以它所在的行或列至少有一个会进行一次操作比如1的坐标为(1,2)、(2,1)、(2,2)、(3,3)
也就是每条边至少有一个端点会被选择(覆盖),问题就变成了二分图的最小点覆盖数问题。代码
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
int n,m;
int mat[600][600];//是否有x连向y的边
int link[600];//与y节点相配对的x节点
int visit[600];//y节点是否被配对了
bool Can(int t)
{
for(int i=1;i<=n;i++)
{
if(visit[i]==0 && mat[t][i]==1)
{
visit[i]=1;
if(link[i]==-1 || Can(link[i]))
{
link[i]=t;
return 1;
}
}
}
return 0;
}
void Match()
{
int ans=0;
for(int i=1;i<=n;i++)
{
memset(visit,0,sizeof(visit));
if(Can(i))ans++;
}
cout<<ans<<endl;
}
int main()
{
int r,c;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(mat,0,sizeof(mat));
memset(link,-1,sizeof(link));
memset(visit,0,sizeof(visit));
for(int i=1;i<=m;i++)
{
scanf("%d%d",&r,&c);
mat[n-r+1][c]=1;//mat数组使用的的是笛卡尔坐标系
}
Match();
}
}