分析
用网络流写二分图匹配,建一个点s,连接二分图的一边,一个点t,连接二分图的另一边。整个图的每一条边的流量都是1。
从s到t的最大流就是ans。
网络流的方法:
Dinic
这个算法的效率是相当高的,算法流程如下:
1、每次以源点为起始点bfs,求出每个点的编号d[i],d[i]表示从源点到i点通过至少几条残余流量大于0的边,能够到达i点。
2、只有那些满足d[u]+1=d[v]的边(u,v)才被视为存在,然后在这里面不断DFS找增广路并增广(其实随便走都可以),如果没有增广路了,那么返回步骤1,如果BFS不到汇点,证明算法结束。
code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<string>
#include<algorithm>
using namespace std;
struct arr{
int x,y,w;
int op;
int next;
}edge[1000000];
int ls[4000];
int v[4000];
int w[4000];
int f[4000];
int queue[5000];
int dis[4000];
int s,t;
int n,m,nn;
int min1;
int ans;
void er(int ww)
{
w[nn]=ww;
}
void add(int x,int y,int w)
{
nn++;
edge[nn].x=x;
edge[nn].y=y;
edge[nn].w=w;
edge[nn].op=nn+1;
edge[nn].next=ls[x];
ls[x]=nn;
v[x]=nn;
er(w);
nn++;
edge[nn].x=y;
edge[nn].y=x;
edge[nn].w=w;
edge[nn].op=nn-1;
edge[nn].next=ls[y];
ls[y]=nn;
v[y]=nn;
er(0);
}
bool bfs()
{
memset(dis,-1,sizeof(dis));
memset(queue,0,sizeof(queue));
int head,tail;
head=0; tail=1;
queue[head]=0;
dis[0]=0;
do
{
head++;
int i=ls[queue[head]];
while (i!=0)
{
if ((w[i]>0)&&(dis[edge[i].y]==-1))
{
dis[edge[i].y]=dis[edge[i].x]+1;
tail++;
queue[tail]=edge[i].y;
if (edge[i].y==t) return true;
}
i=edge[i].next;
}
}while (head<tail);
return false;
}
bool find(int x,int num)
{
if (x==t) return true;
if (x!=s) min1=min(min1,w[num]);
for (int i=v[x];i!=0;i=edge[i].next)
{
int x=edge[i].x;
int y=edge[i].y;
if ((dis[x]+1==dis[y])&&(w[i]!=0)&&(find(y,i)))
{
f[x]=y;
w[i]-=min1;
w[edge[i].op]+=min1;
return true;
}
}
return false;
}
void dinic()
{
ans=0;
while (bfs())
{
min1=2000000000;
find(s,0);
ans+=min1;
}
}
int main()
{
scanf("%d%d",&n,&m);
if ((n==-1)&&(m==-1))
return 0;
int i=0;
int x,y;
while (1==1)
{
i++;
scanf("%d%d",&x,&y);
if ((x==-1)&&(y==-1))
break;
add(x,y,1);
}
s=0;
t=n+m+1;
for (int i=1;i<=n;i++)
add(0,i,1);
for (int i=n+1;i<=n+m;i++)
add(i,t,1);
dinic();
if (ans==0)
printf("No Solution!");
else
printf("%d\n",ans);
return 0;
}