https://vjudge.net/contest/309438#problem/B
题意:一个坐标图上有一些点,一次操作可以覆盖一行或者一列,问至少需要多少次操作
思路:把方阵看做一个特殊的二分图,把每一行当做一个点,每一列当做一个点,行组成一个点集V1,列组成一个点集V2,每当x,y有点时,当做x,y连接的边,选择一个点,那么与这个点相连的线全都被覆盖了,(画个图很好理解)那么这个问题变成选择最少的点覆盖所有的线,即最小点覆盖
最小点覆盖=二分图最大匹配数。
所以直接建立二分图找到最大匹配数即可
#include <iostream>
#include <cstring>
#include <cstdio>
#define fi first
#define se second
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
typedef pair<P, int> LP;
const ll inf = 1e17 + 10;
const int N = 1001;
const ll mod = 10007;
const int base=131;
int n,m,id,t,x,y,k;
int num[N],vis[N],cnt;
int a[N],b[N],c[N];
int ans,flag;
char s[N];
int mp[N][N],link[N];
bool find(int x)
{
int i;
for(i=1;i<=m;i++)
{
if(mp[x][i]&&!vis[i])
{
vis[i]=1;
if(!link[i]||find(link[i]))
{
link[i]=x;
return 1;
}
}
}
return 0;
}
int main()
{
scanf("%d%d",&n,&k);
m=n;
for(int i=1;i<=k;i++)
{
scanf("%d%d",&x,&y);
mp[x][y]=1;
}
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof vis);
if(find(i)) ans++;
}
cout<<ans<<endl;
}