首页 > 题解 > 网络流24题之一 飞行员配对方案问题

网络流24题之一 飞行员配对方案问题

开个大坑。

开始刷网络流24题。

地址:luogu2756

题目背景

第二次世界大战时期..

题目描述

英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其中1 名是英国飞行员,另1名是外籍飞行员。在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合。如何选择配对飞行的飞行员才能使一次派出最多的飞机。对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。

对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。

输入输出格式

输入格式:

第 1 行有 2 个正整数 m 和 n。n 是皇家空军的飞行员总数(n<100);m 是外籍飞行员数。外籍飞行员编号为 1~m;英国飞行员编号为 m+1~n。

接下来每行有 2 个正整数 i 和 j,表示外籍飞行员 i 可以和英国飞行员 j 配合。最后以 2个-1 结束。

输出格式:

第 1 行是最佳飞行员配对方案一次能派出的最多的飞机数 M。接下来 M 行是最佳飞行员配对方案。每行有 2个正整数 i 和 j,表示在最佳飞行员配对方案中,飞行员 i 和飞行员 j 配对。如果所求的最佳飞行员配对方案不存在,则输出‘No Solution!’。

输入输出样例

输入样例#1:

5 10
1 7
1 8
2 6
2 9
2 10
3 7
3 8
4 7
4 8
5 10
-1 -1

输出样例#1:

4
1 7
2 9
3 8
5 10

模型:

二分图的最大匹配。

实现:

在二分图的基础上增加源S和汇T。

1、S向X集合中每个顶点连一条容量为1的有向边。
2、Y集合中每个顶点向T连一条容量为1的有向边。
3、XY集合之间的边都设为从A集合中的点到B集合之中的点,容量为1的有向边。

求网络最大流,流量就是匹配数,所有满流边是一组可行解。

代码:

#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#define M 10010
#define N 2100
#define min(x,y) ((x<y)?(x):(y))
using namespace std;
struct node
{
    int from,to,next,flow;
}e[M];
int tot=-1,st[M],dis[N],q[N][2];
int n,m,x,y,z;
void add(int x,int y,int z)
{
    e[++tot].to=y;
    e[tot].from=x;
    e[tot].flow=z;
    e[tot].next=st[x];
    st[x]=tot;
}
int bfs(int s,int t)
{
    int now;
    queue<int>que;
    memset(dis,-1,sizeof dis);
    dis[s]=1;
    que.push(s);
    while (!que.empty())
    {
        int now=que.front();
        que.pop();
        for (int i=st[now];~i;i=e[i].next)
            if (dis[e[i].to]<0&&e[i].flow>0)
                dis[e[i].to]=dis[now]+1,
                que.push(e[i].to);
    }
    if (dis[t]>0) return 1;
    return 0;
}
int finds(int x,int y,int low)
{
    int ans;
    if (x==y)
        return low;
    for (int i=st[x];~i;i=e[i].next)
        if (e[i].flow>0 && dis[x]+1==dis[e[i].to] && (ans=finds(e[i].to,y,min(low,e[i].flow))))
        {
            e[i].flow-=ans;
            e[i^1].flow+=ans;
            return ans;
        }
    return 0;
}
int Dinic(int s,int t)
{
    int flow=0;
    while(bfs(s,t))
    {
        while(x=finds(s,t,0x3f3f3f3f))
            flow+=x;
    }
    return flow;
}
main()
{
    scanf("%d%d",&m,&n);
    memset(e,-1,sizeof e);
    memset(st,-1,sizeof st);
    int l=0;
    while(1)
    {
        l++;
        scanf("%d%d",&q[l][0],&q[l][1]);
        if (q[l][0]==-1)
            break;
    }
    l--;
    for (int i=1;i<=l;i++)
        add(q[i][0],q[i][1],0x3f3f3f3f),add(q[i][1],q[i][0],0);
    for (int i=1;i<=m;i++)
        add(0,i,1),add(i,0,0);
    for (int i=m+1;i<=n;i++)
        add(i,n+1,1),add(n+1,i,0);
    printf("%d\n",Dinic(0,n+1));
    for (int i=st[0];~i;i=e[i].next)
    {
        if (e[i].flow==0)
            for (int j=st[e[i].to];~j;j=e[j].next)
                if (e[j].flow==0x3f3f3f3f-1)
                    printf("%d %d\n",e[i].to,e[j].to);
    }
}

祝AC.