P2756 飞行员配对问题

题意:寻找最大匹配

思路:转化为二分图匹配问题

新套路:二分图匹配方案的输出:

    for(int i=2;i<=tot*2;i+=2)
    {
        if(ver[i]!=sou&&ver[i^1]!=des)
        if(ver[i]!=des&&ver[i^1]!=sou)
        {
            if(wei[i^1]>0)
            {
                printf("%d %d\n",ver[i],ver[i^1]);
            }
        }
    }

稍微解释一下:就是对于寻找中介连接的边,然后判断后向边有没有流量(也就是这一条边有没有东西流过去)

代码如下:

#include <stdio.h>
#include <algorithm>
#include <cstring>
#define INF 10000000

using namespace std;
const int maxn=1000000;
int head[maxn],next[maxn],wei[maxn],ver[maxn],tot;
int lev[maxn],cur[maxn];
int n,m,ans,sou,des;

inline void add(int x,int y,int w)
{
    ver[++tot]=y;wei[tot]=w;next[tot]=head[x];head[x]=tot;
    ver[++tot]=x;wei[tot]=0;next[tot]=head[y];head[y]=tot;
}
inline bool bfs()
{
    static int que[202],ql=1,qr=1;
    int x,v;
    for(int i=0;i<=n+1;i++) cur[i]=head[i],lev[i]=-1;
    que[ql]=sou;lev[sou]=0;
    for(ql=1,qr=1;ql<=qr;ql++)
    {
        x=que[ql];
        for(int i=head[x];i;i=next[i])
        {
            if(wei[i]>0&&lev[v=ver[i]]==-1)
            {
                lev[v]=lev[x]+1;
                que[++qr]=v;
                if(v==des) return true;
            }
        }
    }
    return false;
}
inline int dinic(int x,int flow)
{
    if(x==des) return flow;
    int res=0,v,delta;
    for(int i=cur[x];i;i=next[i])//这里失误了,应该是cur[x]而不是cur[i] 
    {
        if(wei[i]>0&&lev[x]<lev[v=ver[i]])
        {
            delta=dinic(v,min(flow-res,wei[i]));
            if(delta)
            {
                wei[i]-=delta;wei[i^1]+=delta;
                res+=delta;if(res==flow) break;
            }
        }
    }
    if(res!=flow) lev[x]=-1;
    return res;
}
inline int maxflow()
{
    int res=0;
    while(bfs()) res+=dinic(sou,INF);
    return res;
}
int main()
{
    scanf("%d%d",&m,&n);
    tot=1;sou=0,des=n+1;
    int u,v;
    while(1)
    {
        scanf("%d%d",&u,&v);
        if(u==-1&&v==-1) break;
        add(u,v,1);
    }
    for(int i=1;i<=m;i++) add(sou,i,1);
    for(int i=m+1;i<=n;i++) add(i,des,1);
    ans=maxflow();
    printf("%d\n",ans);
    for(int i=2;i<=tot*2;i+=2)
    {
        if(ver[i]!=sou&&ver[i^1]!=des)
        if(ver[i]!=des&&ver[i^1]!=sou)
        {
            if(wei[i^1]>0)
            {
                printf("%d %d\n",ver[i],ver[i^1]);
            }
        }
    }
    return 0;
}
View Code

 

posted @ 2020-09-05 10:50  ILH  阅读(210)  评论(0)    收藏  举报