P2756 飞行员配对方案问题

题目背景

第二次世界大战时期..

题目描述

英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的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 

思路:

二分图最大匹配的裸题,可以用匈牙利直接求解,同时用linker数组输出具体的方案。

或者用最大流求解,

把外籍飞行员 化为左边的点

英国飞行员 化为右边的点,

即一个左右点之间的最大匹配问题,

然后建立一个超级源点0,将超级源点和所有左边的点相连,流量为1.

建立一个超级汇点n+1,将超级汇点和所有右边的点相连,流量为1.

然后左边和右边的连边即为题目给的可行边,流量也为1.

然后跑最大流,就是最佳匹配方案数。

我是用的ISAP算法跑的网络流。

中间边如果残余流量为0,那么这个边的两个节点就是匹配方案中的一个匹配对。

网络流代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {a %= MOD; if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}inline void getInt(int* p);
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
#define N 1000
#define INF 100000000
struct Edge
{int from, to, cap, flow;
};struct ISAP
{int n, m, s, t;vector<Edge>edges;vector<int>G[N];bool vis[N];int d[N], cur[N];int p[N], num[N]; //比Dinic算法多了这两个数组,p数组标记父亲结点,num数组标记距离d[i]存在几个void addedge(int from, int to, int cap){edges.push_back((Edge) {from, to, cap, 0});edges.push_back((Edge) {to, from, 0, 0});int m = edges.size();G[from].push_back(m - 2);G[to].push_back(m - 1);}int Augumemt(){int x = t, a = INF;while (x != s) //找最小的残量值{Edge&e = edges[p[x]];a = min(a, e.cap - e.flow);x = edges[p[x]].from;}x = t;while (x != s) //增广{edges[p[x]].flow += a;edges[p[x] ^ 1].flow -= a;x = edges[p[x]].from;}return a;}void bfs()//逆向进行bfs{memset(vis, 0, sizeof(vis));queue<int>q;q.push(t);d[t] = 0;vis[t] = 1;while (!q.empty()){int x = q.front(); q.pop();int len = G[x].size();for (int i = 0; i < len; i++){Edge&e = edges[G[x][i]];if (!vis[e.from] && e.cap > e.flow){vis[e.from] = 1;d[e.from] = d[x] + 1;q.push(e.from);}}}}int Maxflow(int s, int t) //根据情况前进或者后退,走到汇点时增广{this->s = s;this->t = t;int flow = 0;bfs();memset(num, 0, sizeof(num));for (int i = 0; i < n; i++)num[d[i]]++;int x = s;memset(cur, 0, sizeof(cur));while (d[s] < n){if (x == t) //走到了汇点,进行增广{flow += Augumemt();x = s; //增广后回到源点}int ok = 0;for (int i = cur[x]; i < G[x].size(); i++){Edge&e = edges[G[x][i]];if (e.cap > e.flow && d[x] == d[e.to] + 1){ok = 1;p[e.to] = G[x][i]; //记录来的时候走的边,即父边cur[x] = i;x = e.to; //前进break;}}if (!ok) //走不动了,撤退{int m = n - 1; //如果没有弧,那么m+1就是n,即d[i]=nfor (int i = 0; i < G[x].size(); i++){Edge&e = edges[G[x][i]];if (e.cap > e.flow)m = min(m, d[e.to]);}if (--num[d[x]] == 0)break; //如果走不动了,且这个距离值原来只有一个,那么s-t不连通,这就是所谓的“gap优化”num[d[x] = m + 1]++;cur[x] = 0;if (x != s)x = edges[p[x]].from; //退一步,沿着父边返回}}return flow;}
};
ISAP gao;
int n, m;int main()
{//freopen("D:\\code\\text\\input.txt","r",stdin);//freopen("D:\\code\\text\\output.txt","w",stdout);du2(m, n);int x, y;while (~scanf("%d %d", &x, &y)){if (x + y == -2){break;}gao.addedge(x, y, 1);}// gao.s = 0;// gao.t = n + 1;repd(i, 1, m){gao.addedge(0, i, 1);}repd(i, m + 1, n){gao.addedge(i, n + 1, 1);}gao.n = n + 2;printf("%d\n", gao.Maxflow(0, n + 1) );repd(i, 1, m){for (auto yy : gao.G[i]){Edge temp =  gao.edges[yy];int v = temp.to;if (v > m && v <= n && temp.flow == 1){printf("%d %d\n", i, v );}}}return 0;
}inline void getInt(int* p) {char ch;do {ch = getchar();} while (ch == ' ' || ch == '\n');if (ch == '-') {*p = -(getchar() - '0');while ((ch = getchar()) >= '0' && ch <= '9') {*p = *p * 10 - ch + '0';}}else {*p = ch - '0';while ((ch = getchar()) >= '0' && ch <= '9') {*p = *p * 10 + ch - '0';}}
}

匈牙利代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {a %= MOD; if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}inline void getInt(int* p);
const int maxn = 10010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
int linker[maxn * 2];
bool used[maxn * 2];
std::vector<int> son[maxn];
bool dfs(int u)
{for (auto v : son[u]) {if (!used[v]) {used[v] = true;if (linker[v] == -1 || dfs(linker[v])) {linker[v] = u;return true;}}}return false;
}int n, m;
int hungarian()
{int res = 0;for (int i = 0; i <= n; i++) {linker[i] = -1;}for (int u = 1; u <= m; u++) {for (int i = 1; i <= n ; i++){used[i] = 0;}// 根据题目判断是否改memsetif (dfs(u)){res++;}}return res;
}
int main()
{//freopen("D:\\code\\text\\input.txt","r",stdin);//freopen("D:\\code\\text\\output.txt","w",stdout);du2(m, n);int x, y;while (~scanf("%d %d", &x, &y)){if (x + y == -2){break;} else{son[x].push_back(y);son[y].push_back(x);}}cout << hungarian() << endl;repd(i, 1, n){// chu(linker[i]);if (linker[i] != -1){printf("%d %d\n", i, linker[i] );}}return 0;
}inline void getInt(int* p) {char ch;do {ch = getchar();} while (ch == ' ' || ch == '\n');if (ch == '-') {*p = -(getchar() - '0');while ((ch = getchar()) >= '0' && ch <= '9') {*p = *p * 10 - ch + '0';}}else {*p = ch - '0';while ((ch = getchar()) >= '0' && ch <= '9') {*p = *p * 10 + ch - '0';}}
}

转载于:https://www.cnblogs.com/qieqiemin/p/11627283.html

洛谷 P2756 飞行员配对方案问题 (二分图/网络流,最佳匹配方案)相关推荐

  1. 洛谷 - P2756 飞行员配对方案问题(二分图最大匹配+路径打印)

    题目链接:点击查看 题目大意:给出n个飞行员,m个外籍飞行员,每个外籍飞行员可以和多个英国飞行员匹配,每架飞机需要两名一名外籍飞行员和一名英国飞行员同时操作,问如何匹配才能使得一次能尽可能多的派出飞机 ...

  2. 洛谷 P2756 飞行员配对方案问题 二分图 匈牙利算法 链式前向星 汉子找妹子模型 最大流模板 FF算法

    题目链接: https://www.luogu.com.cn/problem/P2756 方法一: 算法:1:匈牙利算法 思路:1:汉子找妹子模型 #include<bits/stdc++.h& ...

  3. P2756 飞行员配对方案问题【网络流24题】

    P2756 飞行员配对方案问题 文章目录 题目背景 题解: 代码: 题目背景 第二次世界大战期间,英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相 ...

  4. P2756 飞行员配对方案问题

    题目链接:P2756 飞行员配对方案问题 题意 一共有 n n n 个飞行员,其中有 m m m 个外籍飞行员和 ( n − m ) (n - m) (n−m) 个英国飞行员,外籍飞行员从 1 1 1 ...

  5. 洛谷P2507 [SCOI2008]配对 题解(dp+贪心)

    洛谷P2507 [SCOI2008]配对 题解(dp+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1299251 链接题目地址:洛谷P2507 [S ...

  6. 【洛谷 - P2756】飞行员配对方案问题(网络流最大流,输出方案)

    题干: 题目背景 第二次世界大战时期.. 题目描述 英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其中1 名是英国飞行员,另 ...

  7. 网络流24题(1) P2756 飞行员配对方案问题

    题目链接 题意:求一个最大的二分匹配,网络流最大流,自己造一个源点一个汇点,源点0到1~m流为1,m+1~n到汇点n+1流为1,然后就是题目给出的也是流为1,图就是这样的,套dinic一个板子,但是题 ...

  8. 洛谷P2507 [SCOI2008]配对

    P2507 [SCOI2008]配对 题目背景 四川NOI2008省选 题目描述 你有 n 个整数Ai和n 个整数Bi.你需要把它们配对,即每个Ai恰好对应一个Bp[i].要求所有配对的整数差的绝对值 ...

  9. 【洛谷】P3386 【模板】二分图最大匹配

    题目地址: https://www.luogu.com.cn/problem/P3386 题目描述: 给定一个二分图,其左部点的个数为nnn,右部点的个数为mmm,边数为eee,求其最大匹配的边数.左 ...

最新文章

  1. iPhone程序中的加密处理
  2. Android MVC模式在android系统中的体现
  3. AWS elastic load balancer里的监听器certificate设置
  4. 再见c罗再见梅西_再见,再见,5 * 60 * 1000 //五分钟,再见,再见
  5. 解决-ubuntu 安装redis无法启动
  6. 【python教程入门学习】python基础语法
  7. ffmpeg视频处理
  8. b+树时间复杂度_满二叉树、完全二叉树、二叉搜索树、平衡二叉树
  9. linux 内核/proc
  10. golang windows环境下的配置安装
  11. 表结构设计器(EZDML)1.98版公布
  12. php用户评论系统,php实现文章评论系统
  13. 【RobotStudio学习笔记】(六)有效载荷
  14. c++ opencv 通过网络连接工业相机_使用OpenCV进行手势控制游戏+源码分享
  15. wojilu系统的ORM代码解析-[源代码结构分析,用特性和反射来感知属性-特性介绍篇]...
  16. ASP.NET Ajax 中出现的 sys 未定义(sys undefined)解决方法总结
  17. 环保材料“接棒”汽车电子成主业?路畅科技“等到”金主
  18. python 网络调试助手
  19. 西安电子科技大学计算机应用,西安电子科技大学计算机应用技术考研
  20. C语言火车订票系统开发

热门文章

  1. 使用JPA + Eclipselink操作PostgreSQL数据库
  2. BSP和JSP里的UI元素ID生成逻辑
  3. OpenFOAM程序开发的基本知识(基本术语)
  4. android 启动service报错,Android小经验
  5. vue 如何将参数放到连接上_通过Vue路由传参的两种方式及Vue组件中接收参数的方式...
  6. <学习日记>计算机网络第一章预习记录
  7. python mssql 报表_Python从mssql向SQLite插入表
  8. 直播画面抖动_罗永浩直播带货1.1个亿,企业想玩网络直播,三大专业设备你必须知道...
  9. matlab软件moran值,用matlab求moran并作图的具体步骤
  10. python数据科学指南是什么_《Python数据科学指南》——导读