题解 P2756 【飞行员配对方案问题】

luogu

思路

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; 
        }
    }
}
posted @ 2019-07-19 19:39  G_A_TS  阅读(603)  评论(0编辑  收藏  举报