这道题运用的算法和SSL1338 人员分配【二分图匹配】一样,关键是你怎么样建图!
我们可以思考一个问题:怎样让一颗子弹直接把一行或一列打掉呢?
这时我们考虑匹配的性质,当一个点与另一个点匹配,那么这个点就不能再和其他点匹配(暂时)。
会发现,我们可以直接建图,行放在上,列放在下,当枚举到 i i i 点时,产生匹配,
其他所有点都不能与之匹配,相当于把其他边全部断掉(暂时),这就符合了一颗子弹直接把一行或一列打掉的情况。
所以最大匹配就是答案。
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int v[1000010],ls[1000010],link[1000010];
int n,k,x,y,tot,ans;
struct node
{
int y,next;
}a[1000010];
void add(int x,int y)
{
a[++tot].y=y;
a[tot].next=ls[x];
ls[x]=tot;
}
int dfs(int x)
{
for(int i=ls[x]; i; i=a[i].next)
{
int y=a[i].y;
if(v[y]==0)
{
v[y]=1;
int fa=link[y];
link[y]=x;
if(fa==0||dfs(fa))
return 1;
link[y]=fa;
}
}
return 0;
}
int main()
{
cin>>n>>k;
for(int i=1; i<=k; i++)
{
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i=1; i<=n; i++)
{
memset(v,0,sizeof(v));
dfs(i);
}
for(int i=1; i<=n; i++) //要循环,不然就会出错
if(link[i]!=0)
ans++;
cout<<ans;
return 0;
}