分析:
这和UVa的一道题目是一样的
但是这里我们用匈牙利完成(纯粹是为了练算法)
我们在使用网络流求解的时候,转化成了最小割的问题
具体的建图:
每一行为x部,每一列为y部,
每个小行星就转化成两个部之间的连线
跑最大流即可
然而在使用匈牙利算法的时候,我们的思维也要经过如此转化
而匈牙利说白了就是增广的一个简单实现
(代码短,复杂度比较稳定)
也就是说,想要使用匈牙利算法的前提是你要有一颗网络流的心
(匈牙利可以构造可行解,这是网络流所不及的)
tip
真的再也不想做bzoj的题,全是权限。。。
匈牙利的复杂度在nm~n^3左右,网络流的复杂度玄学
对于算法的选择还是要视情况而定
虽然我们对二分图的定义是无向图
但是在进行匈牙利算法时候,我们要单向连边
测试了一下匈牙利和网络流的复杂度
匈牙利:
网络流:
嗯?好吧,网络流比较厉害,我无f*ck说
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=505;
const int M=10005;
struct node{
int x,y,nxt;
};
node way[M<<1];
int st[N],tot=0,cx[N],cy[N],n,m;
bool vis[N];
void add(int u,int w)
{
tot++;
way[tot].x=u;way[tot].y=w;way[tot].nxt=st[u];st[u]=tot;
//单向边
}
int match(int now)
{
for (int i=st[now];i;i=way[i].nxt)
{
int v=way[i].y;
if (!vis[v]) //一轮匹配 每个点只进行一次
{
vis[v]=1;
if (!cy[v]||match(cy[v]))
{
cx[now]=v; cy[v]=now;
return 1;
}
}
}
return 0;
}
int XYL()
{
int ans=0;
for (int i=1;i<=n;i++)
if (!cx[i]){
memset(vis,0,sizeof(vis));
ans+=match(i);
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
int u,w;
scanf("%d%d",&u,&w);
add(u,w);
}
printf("%d",XYL());
return 0;
}