飞行员配对方案问题 题解
飞行员配对方案问题
这道题来自网络流24题,显然需要使用网络流
建立一个超级原点 S S S 和一个超级汇点 T T T,连边方式如下:
- 对于每个外籍飞行员,连 S → i ( 1 ≤ i ≤ m ) S\to i(1\leq i \leq m) S→i(1≤i≤m),流量为 1 1 1
- 对于每个英国飞行员,连 i → T ( m + 1 ≤ i ≤ n i \to T(m+1\leq i\leq n i→T(m+1≤i≤n,流量为 1 1 1
- 对于每一个配对,连 u → v u\to v u→v,流量为 1 1 1
跑 dinic \operatorname{dinic} dinic 即可
// Problem: P2756 飞行员配对方案问题
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2756
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// https://codeforces.com/problemset/customtest
# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair <int, int> pii;
//# define int long long
# define rd(t) read <t> ()
# define mem(a, b) memset (a, b, sizeof (a))
# define fi first
# define se second
# define lc u << 1
# define rc u << 1 | 1
# define debug printf ("debug\n")
const int N = 105, M = 20005;
template <typename T> inline T read ()
{
T s = 0; int w = 1; char c = getchar ();
for (; !isdigit (c); c = getchar ()) { if (c == '-') w = -1; }
for (; isdigit (c); c = getchar ()) s = (s << 1) + (s << 3) + c - '0';
return s * w;
}
int n, m, S, T;
struct edge { int vtx, nxt, c; } e[M];
int h[N]; int idx = 1;
void add (int u, int v, int c)
{
e[ ++ idx] = {v, h[u], c}; h[u] = idx;
e[ ++ idx] = {u, h[v], 0}; h[v] = idx;
}
int d[N];
int now[N];
int q[N], hh, tt;
bool bfs ()
{
memset (d, -1, sizeof d); d[S] = 0;
now[S] = h[S];
hh = 1, tt = 0; q[ ++ tt] = S;
while (hh <= tt)
{
int u = q[hh ++ ];
for (int i = h[u]; ~i; i = e[i].nxt)
{
int v = e[i].vtx;
if (d[v] == -1 && e[i].c)
{
d[v] = d[u] + 1;
now[v] = h[v];
if (v == T) return 1;
q[ ++ tt] = v;
}
}
}
return 0;
}
int dfs (int u, int lim)
{
if (u == T) return lim;
int flw = 0;
for (int i = now[u]; ~i && flw < lim; i = e[i].nxt)
{
now[u] = i;
int v = e[i].vtx;
if (d[v] == d[u] + 1 && e[i].c)
{
int t = dfs (v, min (e[i].c, lim - flw));
if (!t) d[v] = -1;
e[i].c -= t, e[i ^ 1].c += t, flw += t;
}
}
return flw;
}
int dinic ()
{
int ans = 0, flw;
while (bfs ()) while (flw = dfs (S, 1e9)) ans += flw;
return ans;
}
signed main ()
{
mem (h, -1);
memset (h, -1, sizeof h);
m = rd (int), n = rd (int);
S = 0, 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);
int u, v;
while (scanf ("%d%d", &u, &v) && ~u && ~v) add (u, v, 1);
printf ("%d\n", dinic ());
for (int i = 0; i < idx; i += 2)
{
if (e[i].vtx > m && e[i].vtx <= n && !e[i].c)
printf ("%d %d\n", e[i ^ 1].vtx, e[i].vtx);
}
return 0;
}