网络流纯爱战士揍扁了匈牙利牛头人
原题
核心思想就是创建一个超级源点和超级汇点,超级源点连接外籍飞行员,超级汇点连接嘤国飞行员,把能配合的两个人作为一个连接两种飞行员的一个边.能同时起飞的数量就是S点到T点的最大流了
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10010, M = 200010, inf = 1e8;
int n, m, S, T;
int h[N], e[M], f[M], ne[M], idx;
//h 表头 e边的终点 f边的权值
int q[N], d[N], cur[N];
void add(int a, int b, int c) {
e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx ++ ;
}
bool bfs() {
int hh = 0, tt = 0;
memset(d, -1, sizeof d);
q[0] = S, d[S] = 0, cur[S] = h[S];
while (hh <= tt) {
int t = q[hh ++ ];
for (int i = h[t]; ~i; i = ne[i]) {
int ver = e[i];
if (d[ver] == -1 && f[i]) {
d[ver] = d[t] + 1;//ver是t的下一级,防止回流
cur[ver] = h[ver];
if (ver == T)
return true;
q[ ++ tt] = ver;
}
}
}
return false;
}
int find(int u, int limit) {
if (u == T)
return limit;//到了最终点,不用考虑后面的,上限就是可扩展的量
int flow = 0;
for (int i = cur[u]; ~i && flow < limit; i = ne[i]) {
cur[u] = i; //当前弧优化
int ver = e[i];
if (d[ver] == d[u] + 1 && f[i]) {
int t = find(ver, min(f[i], limit - flow)); //下一条流量的最小值
//或者当前流量限制减去这条路已经花掉的流量中的最小值
if (!t)
d[ver] = -1; //遍历过了
f[i] -= t;
f[i ^ 1] += t;
flow += t;
}
}
return flow;//返回可拓展流量
}
int dinic() {
int r = 0, flow;
while (bfs())//用bfs划分阶级
while (flow = find(S, inf))//不断用dfs进行扩展
r += flow;
return r;
}
int main() {
cin >> m >> n ;
//创建一个超级源点S和一个超级汇点T,将问题转化为从
//s开始,T结束的网络流
S = 0, T = n + 1;
memset(h, -1, sizeof h);
for (int i = 1; i <= m; i++)
add(S, i, 1);
for (int i = m + 1; i <= n; i++)
add(i, T, 1);
int a, b;
while (cin >> a >> b, a != -1) {
add(a, b, 1);
}
cout << dinic() << endl;//输出最大流(即最大的匹配数)
for (int i = 0; i < idx; i += 2) {//枚举正向边,正向边就是idx编号为偶数的边
if (e[i] > m && e[i] <= n && !f[i]) {//保证这个终点编号在n的区域里
cout << e[i ^ 1] << " " << e[i] << endl;//并且有流量(连通)
}
}
}