飞行员配对方案问题
题目大意
Special Judge
有 \(m\) 个外籍飞行员和 \((n-m)\) 个英国飞行员,一架飞机由一个外籍飞行员和一个英国飞行员组成,给定一些外籍和英国飞行员的组合,问怎样才能派出最多的飞机,并给出方案。
这是一道经典的最大流,最小割问题,第一问很简单,难在第二问输出方案
思路
算法一 (匈牙利二分图匹配)
将英国飞行员看作一个点集,外籍飞行员看作另一个点集,跑一边二分图匹配就可以了。
实际上,二分图匹配也是一种特殊的最大流EK算法
时间复杂度 \(O(nm)\)
算法二(最大流dinic)
dinic算法是用于求最大流的一种算法,相比于EK算法,他的速度会快一些。
没学过dinic算法的可以看我这篇博客。
网络流的题目一般都不是难在代码上,而是难在建图,这是这道题的建图:
建立一个源点,连向所有的外籍飞行员,权值为 \(1\)
建立一个汇点,所有的英国飞行员连向它,权值为 \(1\)
根据题目给的关系,将其连边,权值为INF
由于这个图中所有的权值和是确定的,所以就将题目要求转换为了最小割问题,又因为最大流和最小割是等价的,所以跑一遍dinic就可以了。
然后是第二问,首先需要理解,因为跑完dinic后留下的图中一定是无法从源点再次走到汇点的。所以跑完的图中就相当于是最小割的结果,于是只要在图中找到一对关系,使得反边的权值不等于零即可。
时间复杂度 \(O(nm^2)\)
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, m, S = 0, T, ans, dep[N];
struct Edge {
int v, id, w, last, tag;
};
vector<Edge> g[N];
void add(int x, int y, int w) {
g[x].push_back({y, g[y].size(), w, w, 1});
g[y].push_back({x, g[x].size() - 1, 0, 0, 2}); // 注意这里反边的权值要设为0 !!!不然输出方案时可能会错
}
bool bfs() {
memset(dep, 0x3f, sizeof dep);
queue<int> q;
q.push(S);
dep[S] = 1;
while (q.size()) {
int u = q.front(); q.pop();
for (auto t : g[u]) {
int v = t.v, w = t.w;
if (dep[v] != 0x3f3f3f3f || !w) continue;
dep[v] = dep[u] + 1;
q.push(v);
}
}
return dep[T] != 0x3f3f3f3f;
}
int dfs(int x, int flow) {
if (x == T) return flow;
int sum = 0;
for (auto &t : g[x]) {
int y = t.v, w = t.w, id = t.id;
if (!w || dep[y] != dep[x] + 1) continue;
int f = dfs(y, min(flow, w));
if (!f) continue;
sum += f;
flow -= f;
t.w -= f;
g[y][id].w += f;
if (!flow) break;
}
return sum;
}
void dinic() {
while (bfs()) {
ans += dfs(S, 0x3f3f3f3f);
}
}
int main() {
cin >> m >> n; T = n + 1;
for (int i = 1; i <= m; i++) add(S, i, 1);
for (int i = m + 1; i <= n; i++) add(i, T, 1); // 这里一定要写add(i, T, 1),而不能写成add(T, i, 1),要不然你可能会和我一样得到63分的高分
int u, v;
while (cin >> u >> v) {
if (u == -1) break;
add(u, v, 0x3f3f3f3f);
}
dinic();
cout << ans << endl;
for (int i = 1; i <= n; i++)
for (auto t : g[i]) {
if (t.tag == 1) continue;
if (t.w != 0 && t.v != T && t.v != S) {
int x = min(i, t.v), y = max(i, t.v);
cout << x << " " << y << endl;
}
}
return 0;
}

浙公网安备 33010602011771号