飞行员配对问题[网络流24题之1]
2016-05-18 13:39
330 查看
问题描述:
第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的 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! 。
输入文件示例 :
5 101 7
1 8
2 6
2 9
2 10
3 7
3 8
4 7
4 8
5 10
-1 -1
输出文件示例
41 7
2 9
3 8
5 10
分析 :
这个题目是一个经典的网络流问题,若把英国飞行员和外籍飞行员之间连一条边就是一个多源点多汇点的网络流问题,建模过程如下1 :把配对的飞行员之间连一条容量为 1 的边
2 :新增一个源 S ,把 S 与外籍飞行员之间连一条容量为 1 的边
3 :新增一个汇 T ,把 T 与英国飞行员之间连一条容量为 1 的边
最后求出图中的最大流即为最多配对数。求最大流我用的是 dinic 算法其中因为任意一个飞行员只能与其他飞行员配对一次,所以边的容量为 1 。
至于输出配对方案的话,直接在图中寻找那些流量为 1 的边即可。
代码 :
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int inf = 0x3f3f3f3f; int n,m; int tot = 1; int ans; int c[1147]; int head[1147],nxt[2247],to[2247],wei[2247]; int cur[1147]; queue<int> que; int read(); void add(int,int); bool bfs(); int dinic(int,int); int main(){ n=read();m=read(); for(int i=1;i<=n;++i) add(1,i+1); for(int i=n+1;i<=m;++i) add(i+1,m+2); int a,b; a=read();b=read(); while(a!=-1 && b!=-1){ a++;b++; add(a,b); a=read();b=read(); } int flag; while(bfs()){ flag = 1; while(flag){ memcpy(cur,head,sizeof head); flag = dinic(1,inf); ans += flag; } } if(ans){ printf("%d",ans); for(int i=head[1];i;i=nxt[i]) if(!wei[i]) for(int j=head[to[i]];j;j=nxt[j]) if(!wei[j]){ printf("\n%d %d",to[i],to[j]); break; } } else printf("No Solution!"); return 0; } int read(){ int in = 0; int flag = 1; char ch = getchar(); while(ch>'9'||ch<'0'){ if(ch=='-'){ ch = getchar(); flag = -1; break; } ch = getchar(); } while(ch>='0'&&ch<='9'){ in = in*10+ch-'0'; ch = getchar(); } return in*flag; } void add(int from,int tp){ ++tot;nxt[tot]=head[from];head[from]=tot;to[tot]=tp;wei[tot]=1; ++tot;nxt[tot]=head[tp];head[tp]=tot;to[tot]=from;wei[tot]=0; } bool bfs(){ int now; memset(c,0,sizeof c); que.push(1); c[1] = 1; do{ now = que.front(); for(int i=head[now];i;i=nxt[i]) if(!c[to[i]] && wei[i]){ c[to[i]] = c[now]+1; que.push(to[i]); } que.pop(); }while(!que.empty()); return c[m+2]; } int dinic(int place,int low){ if(place == m+2) return low; int lower; for(int &i=cur[place];i;i=nxt[i]) if(c[to[i]]==c[place]+1 && wei[i]){ lower = dinic(to[i],min(low,wei[i])); if(lower){ wei[i] -= lower; wei[i^1] += lower; return lower; } } return 0; }
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- 解析C++中派生的概念以及派生类成员的访问属性