[SMOJ2205]飞行员配对方案问题(二分图最大匹配)
来源:互联网 发布:库里总决赛场均数据 编辑:程序博客网 时间:2024/05/16 13:59
这题是典型的二分图最大匹配问题,虽然也有专门求解这类问题的算法,但也可以直接用我们已学过的最大流解决。
题目的大意是有
我们可以把外籍飞行员和英国飞行员抽象为两类不同的点,“能配合”的关系则是从代表外籍的点向代表英国的点连一条容量为 1 的边。例如,对于样例:
可以发现一个规律,左边的都是外籍飞行员,右边的都是英国飞行员。左边的点之间互相没有连边,右边的点之间也没有。只有从左边的点连向右边的点的边,这样的图就叫做二分图。选取其中若干边,使任意两条边都不依附于同一个顶点,要求选取尽量多的边,这样的问题就是二分图最大匹配。
不妨把“从左边的点流一个单位的流量到右边的点”视作“左边这个点的外籍飞行员与右边这个点的飞行员合作”,这就是为什么要连边的容量为 1。
那么,要使合作的对数尽可能多,当然就要求流到右边所有点的流量总和最大,而且左边每个点最多只能有一个单位流量发出(不可能同时与多人合作)。
这样的问题我们是无法直接求解的,但可以通过一个小技巧:增加超级源点
参考代码:
//prog81#include <algorithm>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>using namespace std;const int INF = 0x3f3f3f3f;const int MAXN = 100 + 10;struct Edge { Edge *next; int cap; int dest;// Edge () : next(NULL), cap(0), dest(0) {}} edges[MAXN * MAXN], *current, *first_edge[MAXN];int m, n;void insert(int u, int v, int c) { current -> next = first_edge[u]; current -> cap = c; current -> dest = v; first_edge[u] = current ++;// printf("%d %d\n", u, first_edge[u]);}Edge *counterpart(Edge *x) { //求反向边,利用了正反向边在 edges 数组中是相邻储存的特性 return edges + ((x - edges) ^ 1);}bool vis[MAXN];int dfs(int u, int f) {// printf("%d %d\n", u, f); if (u == n + 1) return f; //到达汇点,本次增广结束 if (vis[u]) return 0; else vis[u] = true; for (Edge *p = first_edge[u]; p; p = p -> next) { int v = p -> dest; if (p -> cap) if (int res = dfs(v, min(f, p -> cap))) { //找得到一条 u 到 t 的路径,流量为 res// printf("%d\n", res); p -> cap -= res; counterpart(p) -> cap += res; return res; //每次找一条 } } return 0; //无增广路}int main(void) { freopen("2205.in", "r", stdin); freopen("2205.out", "w", stdout); scanf("%d%d", &m, &n); current = edges; fill(first_edge, first_edge + n + 1, (Edge*)0);// printf("%d %d\n", m, n); for (int i = 1; i <= m; i++) { insert(0, i, 1); insert(i, 0, 0); } //printf("%d\n", first_edge[0]); for (int i = m + 1; i <= n; i++) { insert(i, n + 1, 1); insert(n + 1, i, 0); } int i, j; while (~scanf("%d%d", &i, &j) && i > 0){// insert(0, i, 1); insert(i, 0, 0); insert(i, j, 1); insert(j, i, 0);// insert(j, n + 1, 1); insert(n + 1, j, 0); } int ans = 0; while (true) { //不断增广,直到找不到增广路 memset(vis, false, sizeof vis); if (int res = dfs(0, INF)) ans += res; else break; } if (!ans) puts("No Solution!"); else { printf("%d\n", ans);// for (int i = 1; i <= m; i++)// for (Edge *p = first_edge[i]; p; p = p -> next)// if (!p -> cap && p -> dest) { printf("%d %d\n", i, p -> dest);/* break;*/ } } return 0;}
从这题中可以发现网络流的一个特征,它的题目难点在于“建模”。如何将问题的模型进行转化,从而对网络中的点、边、流赋予具体的含义,是重中之重。
因此,网络流题目的描述将不会再像之前的图论题一样,有非常明显的顶点、边的暗示,而是要靠自己去探索和发现。这就需要多加练习,掌握其中的规律。
- [SMOJ2205]飞行员配对方案问题(二分图最大匹配)
- 飞行员配对方案问题(二分图的最大匹配)
- 飞行员配对方案问题(二分图最大匹配)
- 一、飞行员配对方案问题 [二分图的最大匹配]
- [网络流24题] 飞行员配对方案问题 最大流 二分图最大匹配
- 飞行员配对方案问题(二分图)
- 飞行员配对方案问题 网络流||二分图匹配
- 1.飞行员配对 二分图匹配(输出方案)/最大流斩
- 2006 飞行员配对(二分图最大匹配)
- 2006 飞行员配对(二分图最大匹配)
- 51Nod-2006-飞行员配对(二分图最大匹配)
- [题解] [网络流二十四题(一)] 飞行员配对方案问题 (二分图匹配)
- P2756 飞行员配对方案问题(二分图??网络流??)
- 51nod 2006 飞行员配对(二分图最大匹配)
- 51nod2006 飞行员配对(二分图最大匹配)匈牙利算法
- 51NOD 2006 飞行员配对(二分图最大匹配)
- 51NOD2006 飞行员配对(二分图最大匹配)
- 51NOD-2006 飞行员配对(二分图最大匹配)
- 深入理解volatile关键字
- swift3实现照片多选,史上最赞(TGPhotoPicker)
- mysql的一些基本命令
- 实现日夜间转换获取数据上下刷新(values-colors)
- c++ primer plus阅读笔记6---内联函数引用变量
- [SMOJ2205]飞行员配对方案问题(二分图最大匹配)
- Linux三剑客之SED
- 用java打印实心菱形
- socket编程
- python 基础知识总结
- centos编译安装subversion
- 使用Spring Boot与否,初始化Spring应用的对比
- JS数字时钟
- 2017.8.13个人感悟