题解
二分图匹配。
设一个超级源点和一个超级汇点,建立源点->外籍飞行员->英国飞行员->汇点的网络。所有边的容量设为1。此时,每单位流到汇点的流量即代表一对合法配对,配对间互不干扰。
所以跑最大流即可得到最大匹配数。若想得到谁和谁配对的方案,则看看哪条边流量为0即可。
代码
#include <cstdio>
#include <cstring>
const int maxn=200+10;
const int maxm=10000+10;
const int INF=0x3f3f3f3f;
int cur[maxn],head[maxn],nxt[maxm<<1],to[maxm<<1],val[maxm<<1];
int dep[maxn];
int n,m,s,t;
int tot=1,cnt=0;
struct edge
{
int u,v;
edge() {}
edge(int x,int y) {u=x,v=y;}
}e[maxm];
struct Queue
{
int a[maxn];
int l,r;
Queue() {l=1,r=0;}
void push(int x) {a[++r]=x;}
void pop() {l++;}
int front() {return a[l];}
bool empty() {return l>r;}
}q;
inline int min(int x,int y) {return x<y?x:y;}
void add(int u,int v,int w)
{
nxt[++tot]=head[u];
head[u]=tot;
to[tot]=v;
val[tot]=w;
}
bool bfs()
{
memset(dep, 0x3f, sizeof(dep));
dep[s]=0;
q=Queue();
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
for (int i=head[u];i;i=nxt[i])
{
int v=to[i];
if (val[i]&&dep[v]>dep[u]+1)
{
dep[v]=dep[u]+1;
q.push(v);
}
}
}
return dep[t]<INF;
}
int dfs(int u,int minf)
{
if (u==t)
return minf;
int used=0;
for (int &i=cur[u];i;i=nxt[i])
{
int v=to[i];
if (val[i]&&dep[v]==dep[u]+1)
{
int flow=dfs(v, min(minf-used, val[i]));
if (flow)
{
used+=flow;
val[i]-=flow;
val[i^1]+=flow;
if (used==minf)
break;
}
}
}
return used;
}
int main()
{
scanf("%d%d",&m,&n);
s=0,t=m+n+1;
int u=-1,v=-1;
while(scanf("%d%d",&u,&v)&&u!=-1)
{
add(u, v, 1),add(v, u, 0);
e[++cnt]=edge(u, v);
}
for (int i=1;i<=m;i++)
add(s, i, 1),add(i, s, 0);
for (int i=m+1;i<=m+n;i++)
add(i, t, 1),add(t, i, 0);
int maxflow=0;
while(bfs())
{
for (int i=0;i<=m+n;i++)
cur[i]=head[i];
maxflow+=dfs(s, INF);
}
printf("%d\n",maxflow);
for (int i=1;i<=cnt;i++)
if (!val[i<<1])
printf("%d %d\n",e[i].u,e[i].v);
return 0;
}