洛谷-2756 飞行员配对方案问题

本文探讨了一种解决英军飞行员配对问题的算法,旨在通过最大化匹配来提高空中作战效率。外籍飞行员与英国飞行员之间的配合关系被抽象为图论中的最大匹配问题,通过构建特定的图并运用最大流算法,寻找最优的飞行员配对方案。
摘要由CSDN通过智能技术生成

题目描述
英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其中1 名是英国飞行员,另1名是外籍飞行员。在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合。如何选择配对飞行的飞行员才能使一次派出最多的飞机。对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。
对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。
输入输出格式
输入格式:
第 1 行有 2 个正整数 m 和 n。n 是皇家空军的飞行员总数(n<100);m 是外籍飞行员数(m<=n)。外籍飞行员编号为 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

解释:经典网络24题,最大匹配问题,对外籍和英建一条流量为1的边,最后在建立超级汇点和超级据点,跑最大流就好了。对于结果我们检查图的边,容量为0的边为选中匹配,去掉超级汇点和超级聚点输出就好了

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
const int INF=9999999;
int s,t,cnt,n,m;//s为源点,t为汇点
struct node{
    int from;
    int next=-1;//初始化为-1,如果访问到了-1,则需要退出
    int to;
    int w;
};
int head[maxn],q[maxn],deth[maxn];
node edge[maxn];
void init(){
    cnt=-1;
    memset(head,-1,sizeof(head));
}
void add(int x,int y,int z){
    cnt++;
    edge[cnt].from=x;
    edge[cnt].to=y;//终点
    edge[cnt].next=head[x];//上一条边
    edge[cnt].w=z;//边权
    head[x]=cnt;//起点
}
int bfs(){
    memset(deth,0,sizeof(deth));//deth记录深度
    queue<int> q;
    while(!q.empty())
        q.pop();
    deth[s]=1;
    q.push(s);
    do{
        int u=q.front();
        q.pop();
        for(int i=head[u];i!=-1;i=edge[i].next){
            if(edge[i].w>0&&deth[edge[i].to]==0){
                deth[edge[i].to]=deth[u]+1;
                q.push(edge[i].to);
            }
        }
    }
    while(!q.empty());
    if(deth[t]!=0)//当汇点的深度不存在时,说明不存在分层图,同时也说明不存在增广路
        return 1;
    else
        return 0;
}
int dfs(int u,int dist){
    if(u==t)
        return dist;
    for(int i=head[u];i!=-1;i=edge[i].next){
        if((deth[edge[i].to]==deth[u]+1)&&(edge[i].w!=0)){
            int di=dfs(edge[i].to,min(dist,edge[i].w));
            if(di>0){
                edge[i].w-=di;
                edge[i^1].w+=di;
                return di;
            }
        }
    }
    return 0;//否则说明没有增广路,返回0
}
int dinic(int S,int T){
    s=S;t=T;
    int ans=0;
    while(bfs())
        while(int di=dfs(s,INF))
            ans+=di;
    return ans;
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m;
    int x,y;
    init();
    while(cin>>x>>y){
        if(x==-1&&y==-1) break;
        add(x,n+y,1);
        add(n+y,x,0);
    }
    for(int i=1;i<=n;i++){
        add(0,i,1);
        add(i,0,0);
    }
    for(int i=1;i<=m;i++){
        add(i+n,n+m+1,1);
        add(n+m+1,i+n,0);
    }
    cout<<dinic(0,m+n+1)<<endl;
    for(int i=0;i<=cnt;i+=2){
        if(edge[i].w==0&&edge[i].from!=s&&edge[i].to!=t) cout<<edge[i].from<<" "<<edge[i].to-n<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值