飞行员配对问题
成绩 10 开启时间 2020年04月21日 星期二 10:10 折扣 0.8 折扣时间 2020年05月30日 星期六 23:55 允许迟交 否 关闭时间 2020年05月30日 星期六 23:55 问题描述: 第二次世界大战时期, 英国皇家空军从沦陷国征募了大量外籍飞行员. 由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2名飞行员, 其中一名是英国飞行员, 另一名是外籍飞行员, 在众多的飞行员中, 每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合. 如何选择配对的飞行员才能使一次派出最多的飞机.
算法设计: 对于给定的外籍飞行员与英国飞行员的配合情况, 找出皇家空军能派出最多的飞行员数.
数据输入: 第1行有2个正整数m和n. n是皇家空军的飞行员总数(n<100); m是外籍飞行员数. 外籍飞行员编号1~m, 英国飞行员编号m+1~n. 接下来每行2个整数i和j, 表示外籍飞行员i可以与英国飞行员j配合. 最后以2个-1结束.
结果输出: 皇家空军能派出最多的飞行员数.
测试输入 期待的输出 时间限制 内存限制 额外进程 测试用例 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 ↵
以文本方式显示
- 4↵
1秒 64M 0
这是一个二分图的匹配问题,可以转化为最大流的算法取求解,也可以直接使用匈牙利算法。本文直接使用匈牙利算法实现。
关于算法的原理与过程理解可以看看这一篇文章:匈牙利算法(简单易懂)。匈牙利算法还是简单易懂的,本质上就是贪心。下面直接粘上匈牙利算法的AC代码,配合友好的注释应该很好懂啦~
//匈牙利算法解决二部图的最大流问题
#include <cstdio>
#include <cstring>
#define MAXN 105
int m, n; //二部图左侧有m个,总计有n个
bool connected[MAXN][MAXN]; //图的连接关系
int pre[MAXN] = {0}; //next[j]=i:左侧的 i 点与右侧的 j 点匹配
/* 处理输入与初始化 */
void Init() {
scanf("%d %d", &m, &n);
int i, j;
while (true) {
scanf("%d %d", &i, &j);
if (i == -1 && j == -1)
break;
connected[i][j] = true;
}
}
bool vis[MAXN];
/* 寻找左侧的点与右侧匹配 */
bool Find(int left) {
//依次遍历右部顶点
for (int right = m + 1; right <= n; right++) {
//寻找 相邻 且 此次查找没有被考虑过 的右侧点
if (connected[left][right] && !vis[right]) {
vis[right] = true;
//寻找 没有匹配 或 该点的匹配点可以另有匹配 的右侧点
if(pre[right] == 0 || Find(pre[right])) {
pre[right] = left; //匹配
return true;
}
}
}
return false;
}
int CalcAns(){
int ans = 0;
/* 讨论每一个左部顶点 */
for(int left = 1; left <= m; left++) {
memset(vis, false, sizeof(vis)); //每次寻找前需要初始化
if(Find(left)) //如果能找到
ans++; //匹配数字加一
}
return ans;
}
int main() {
Init();
printf("%d\n", CalcAns());
}