P2756 飞行员配对方案问题【二分匹配】【网络流Dinic、EK详解】【萌新初写】

题目链接

  对于二分匹配,这是一道模版题(SPJ)。

二分匹配代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef long long ll;
const int maxN=105;
int N,M;
int fa[maxN];
vector<int> vt[maxN];
bool vis[maxN];
bool match(int u)
{
    int len=(int)vt[u].size();
    for(int i=0; i<len; i++)
    {
        int v=vt[u][i];
        if(vis[v]) continue;
        vis[v]=true;
        if(fa[v]==-1 || match(fa[v]))
        {
            fa[v]=u;
            return true;
        }
    }
    return false;
}
int Hungery()
{
    memset(fa, -1, sizeof(fa));
    int ans=0;
    for(int i=1; i<=M; i++)
    {
        memset(vis, false, sizeof(vis));
        if(match(i)) ans++;
    }
    return ans;
}
int main()
{
    while(scanf("%d%d",&N,&M)!=EOF)
    {
        int e1,e2;
        while(scanf("%d%d",&e1,&e2)!=EOF)
        {
            if(e1==-1 && e2==-1) break;
            vt[e2].push_back(e1);
        }
        int k=0;
        if((k=Hungery())==0) { printf("No Solution!\n"); continue;}
        else printf("%d\n",k);
        for(int i=1; i<=M; i++)
        {
            if(fa[i]==-1) continue;
            printf("%d %d\n", i, fa[i]);
        }
    }
    return 0;
}

 

接下来讲一下,关于网络流Dinic的做法:

  关于网络流,我用的是Dinic算法,这里用EK算法。。。也行(回头给补上去),我们通过bfs找到层,然后用邻接表的方式去记录边的关系,这里用到了个小操作,就是初始化边,我们知道一个网络流之所以能不断的更新,并且让值无限的变大就是有反向弧这么个东西,反向弧在这道问题中存在{ -1, 0, 1 },这样的取值,我这么处理,初始化所有边的值为“-1”,然后对于有关联的两个飞行员间,我们正向定义为“1”、逆向为“0”,这样,就不会遇到无限循环在{ 0,1 }之间了,并且,这么做的目的可以方便于最后的寻找,假如i->j这条边的值为0,说明被用上了,就输出这两个节点就是了。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef long long ll;
const int INF=50000;
const int maxN=205;
int N,M;        //N个英飞,M个外飞
int dis[maxN], r[maxN][maxN], cot=0, tot;
bool bfs()
{
    queue<int> que;
    memset(dis, -1, sizeof(dis));
    dis[0]=1;
    que.push(0);
    while(!que.empty())
    {
        int u=que.front();
        que.pop();
        for(int i=1; i<=tot; i++)
        {
            if(r[u][i]>0 && dis[i]==-1)
            {
                dis[i]=dis[u]+1;
                que.push(i);
            }
        }
    }
    return dis[tot]>0?true:false;
}
int dfs(int x, int maxFlow)
{
    if(x==tot) return maxFlow;
    int res;
    for(int i=1; i<=tot; i++)
    {
        if(r[x][i]>0 && dis[i]==dis[x]+1 && (res = dfs(i, min(maxFlow, r[x][i]))) )
        {
            r[x][i]-=res;
            r[i][x]+=res;
            return res;
        }
    }
    return 0;
}
int main()
{
    while(scanf("%d%d",&M,&N)!=EOF)
    {
        tot=N+1;
        memset(r, -1, sizeof(r));
        memset(dis, -1, sizeof(dis));
        int e1,e2;      cot=0;
        while(scanf("%d%d",&e1,&e2)!=EOF)
        {
            if(e1==-1 && e2==-1) break;
            r[e1][e2]=1;
            r[e2][e1]=0;
            r[0][e1]=1;
            r[e2][tot]=1;
        }
        int res=0;
        while(bfs())
        {
            res=dfs(0, INF);
            cot+=res;
        }
        printf("%d\n",cot);
        for(int i=1; i<=M; i++)
        {
            for(int j=M+1; j<=tot; j++)
            {
                if(r[i][j]==0) printf("%d %d\n",i,j);
            }
        }
    }
    return 0;
}

 

网络流EK的代码:

  EK的思路与Dinic的思路相同,写EK一是为了加深自己的印象,二是看写EK的博主不多,于是就写了下,便于广大擅长EK读者阅读。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef long long ll;
const int INF=50000;
const int maxN=205;
int N,M;        //N个英飞,M个外飞
int r[maxN][maxN], flow[maxN], pre[maxN], cot=0, tot;
int bfs()
{
    queue<int> Q;
    memset(pre, -1, sizeof(pre));
    pre[0]=0;
    flow[0]=INF;
    Q.push(0);
    while(!Q.empty())
    {
        int u=Q.front();        Q.pop();
        if(u==tot) break;
        for(int i=1; i<=tot; i++)
        {
            if(r[u][i]>0 && pre[i]==-1)
            {
                flow[i]=min(r[u][i], flow[u]);
                pre[i]=u;
                Q.push(i);
            }
        }
    }
    return pre[tot]>0?flow[tot]:(-1);
}
int maxFlow()
{
    int incr;       //流
    int sumFlow=0;
    while( (incr=bfs())!=-1 )
    {
        int k=tot;
        while(k)
        {
            int last=pre[k];
            r[last][k]-=incr;
            r[k][last]+=incr;
            k=last;
        }
        sumFlow+=incr;
    }
    return sumFlow;
}
int main()
{
    while(scanf("%d%d",&M,&N)!=EOF)
    {
        tot=N+1;
        memset(r, -1, sizeof(r));
        int e1,e2;      cot=0;
        while(scanf("%d%d",&e1,&e2)!=EOF)
        {
            if(e1==-1 && e2==-1) break;
            r[e1][e2]=1;
            r[e2][e1]=0;
            r[0][e1]=1;
            r[e2][tot]=1;
        }
        printf("%d\n",maxFlow());
        for(int i=1; i<=M; i++)
        {
            for(int j=M+1; j<=N; j++)
            {
                if(r[i][j]==0) printf("%d %d\n",i, j);
            }
        }
    }
    return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值