题解 P2756 【飞行员配对方案问题】
思路
EK算法解二分图匹配
建立超级源点S和超级汇点T跑EK即可,答案在EK函数中记录
Code
#include<bits/stdc++.h>
using namespace std;
int inf=2147483647;
int n,m,ip1,ip2,S,T,ans;
int tot=1,head[1000010],bj[1000010],ansk[1000010];
struct Edge
{
int to,d,next;
}edge[1000010];
struct Pre
{
int X,E;
}pre[1000010];
void addedge(int st,int en,int D)
{
edge[++tot].to=en;
edge[tot].d=D;
edge[tot].next=head[st];
head[st]=tot;
}
int bfs()
{
queue<int>q;
memset(bj,0,sizeof(bj));
memset(pre,-1,sizeof(pre));
bj[S]=1;
q.push(S);
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=head[now];i;i=edge[i].next)
{
int To=edge[i].to;
if(edge[i].d&&!bj[To])
{
pre[To].X=now;
pre[To].E=i;
if(To==T)
{
return 1;
}
bj[To]=1;
q.push(To);
}
}
}
return 0;
}
void EK()
{
ans=0;
while(bfs())
{
int MIN=inf;
for(int i=T;i!=S;i=pre[i].X)
{
MIN=min(MIN,edge[pre[i].E].d);
}
for(int i=T;i!=S;i=pre[i].X)
{
ansk[pre[i].X]=i;
edge[pre[i].E].d-=MIN;
edge[pre[i].E^1].d+=MIN;
}
ans+=MIN;
}
}
int main()
{
scanf("%d%d",&m,&n);
S=0;
T=n+m+1;
for(;;)
{
scanf("%d%d",&ip1,&ip2);
if(ip1==-1&&ip2==-1)
{
break;
}
addedge(ip1,ip2,1);
addedge(ip2,ip1,0);
}
for(int i=1;i<=m;i++)
{
addedge(S,i,1);
addedge(i,S,0);
}
for(int i=m+1;i<=n;i++)
{
addedge(i,T,1);
addedge(T,i,0);
}
EK();
cout<<ans<<endl;
for(int i=1;i<=m;i++)
{
if(ansk[i])
{
cout<<i<<" "<<ansk[i]<<endl;
}
}
}