原题链接
- 题解:建图就类似二分图找最大匹配,然后如果输出方案的话,那就是残留网络中流量为0的正向边就是使用的,所以直接找即可。
- 代码:
#include <iostream>
#include <queue>
#include <map>
#include <cstring>
using namespace std;
#define int long long
map<int,int>mp;
const int N = 2200, M = 220000;
const int inf = 99999999999;
int n, nn, S, T;
int h[M], ne[M], to[M], f[M], idx;
void add(int u, int v, int w) {
ne[idx] = h[u], to[idx] = v, f[idx] = w, h[u] = idx ++;
ne[idx] = h[v], to[idx] = u, f[idx] = 0, h[v] = idx ++;
}
int d[N],cur[N];
queue<int>q;
bool bfs() {
while (!q.empty())q.pop();
q.push(S);
memset(d, -1, sizeof d);
d[S] = 0;
cur[S] = h[S];
while (!q.empty()) {
auto u = q.front();
q.pop();
for (int i = h[u]; ~i; i = ne[i]) {
int v= to[i];
if (d[v] == -1 && f[i]) {
d[v] = d[u] + 1;
cur[v] = h[v];
if (v == T)return 1;
q.push(v);
}
}
}
return 0;
}
int ans[N];
int ans_cnt = 0;
int dfs(int u, int limit) {
if (u == T)return limit;
int flow = 0;
for (int i = cur[u]; ~i && flow < limit; i = ne[i]) {
int v = to[i];
cur[u] = i;
if (f[i] && d[v] == d[u] + 1) {
int t = dfs(v, min(f[i], limit - flow));
if (!t)d[v] = -1;
f[i] -= t;
f[i^1] += t;
flow += t;
}
}
if (u > n && u <= nn && flow ==1) {
ans[++ans_cnt] = u;
} else if (u >0 && u <= n && flow == 1) {
ans[++ans_cnt] = u;
}
return flow;
}
int dinic() {
int ret = 0, flow;
while (bfs()) {while (flow = dfs(S, inf))ret += flow;}
return ret;
}
signed main() {
memset(h, -1, sizeof h);
scanf("%lld%lld%", &n, &nn);
int u, v;
S = 0, T = nn + 1;
while (scanf("%lld%lld", &u, &v)) {
if (u == -1 && v == -1)break;
add(u, v , 1);
}
for (int i = 1; i <= n; i ++) {
add(S, i, 1);
}
for (int j = n + 1; j <= nn; j ++) {
add(j, T, 1);
}
printf("%lld
", dinic());
for (int i = 0; i < idx; i += 2) {
if (to[i ^ 1] <= n && to[i]> n && !f[i]) {
printf("%d %d
", to[i ^ 1], to[i]);
}
}
}