// compile: make data
// run: ./data < data.in
#include <bits/stdc++.h>
using namespace std;
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
#ifdef LOCAL
#include <debug/codeforces.h>
#define debug(x...) _debug_print(#x, x);
#define Debug(x...) _debug_print_format(#x, x);
#else
#define debug(x...)
#define Debug(x...)
#endif
template<typename...Args> void print_(Args...args){((cout<<args<<" "),...)<<endl;}
#define VI vector<int>
#define VII vector<vector<int>>
#define VIII vector<vector<vector<int>>>
#define rep(i,a,b) for(int i=(a);i<(int)(b);++i)
#define sz(v) ((int)(v).size())
#define print(...) print_(__VA_ARGS__);
#define FIND(a, x) ((find(a.begin(),a.end(),(x))!=a.end())?1:0)
#define cmin(x,...) x=min({(x), __VA_ARGS__})
#define cmax(x,...) x=max({(x), __VA_ARGS__})
#define INTMAX (int)(9223372036854775807)
#define INF (int)(1152921504606846976)
#define double long double
#define int long long
#define MAXN 200010
struct network {
struct node {
int u, v, cap, f, w;
int idx;
bool operator<(const node &other) const {return w < other.w; }
bool operator==(const node &other) const {return v == other.v && w == other.w; }
};
vector<vector<node>> e;
vector<vector<int>> invid;
node &inv(node &edge) {return e[edge.v][invid[edge.u][edge.idx]]; }
int n, S, T;
vector<int> dep, cur;
network(int V, int start = -1, int end = -1) {
n = V;
S = ~start ? start : 0;
T = ~end ? end : n - 1;
e.resize(n), invid.resize(n), dep.resize(n), cur.resize(n);
}
void add_edge(int u, int v, int f, int w = 1) {
e[u].push_back(node{u, v, f, 0, w, sz(e[u])});
e[v].push_back(node{v, u, 0, 0, w, sz(e[v])});
invid[u].push_back(sz(e[v]) - 1);
invid[v].push_back(sz(e[u]) - 1);
}
int maxflow() {
auto bfs = [&]() {
queue<int> q; q.push(S);
fill(dep.begin(), dep.end(), 0); dep[S] = 1;
while (!q.empty()) {
int u = q.front(); q.pop();
for (auto &edge: e[u]) {
int v = edge.v;
if (!dep[v] && (edge.cap > edge.f)) {
dep[v] = dep[u] + 1;
q.push(v);
}
}
}
return dep[T];
};
function<int(int, int)> dfs = [&](int u, int flow) {
if (u == T || !flow) return flow;
int ret = 0;
for (int &i = cur[u]; i < sz(e[u]); ++i) {
auto &edge = e[u][i];
int v = edge.v, d;
if (dep[v] == dep[u] + 1 && (d = dfs(v, min(flow-ret, edge.cap-edge.f)))) {
ret += d, edge.f += d;
flow -= d, inv(edge).f -= d;
if (!flow) break;
}
}
if (!ret) dep[u] = INF;
return ret;
};
int ans = 0;
while (bfs()) {
fill(cur.begin(), cur.end(), 0);
ans += dfs(S, INF);
}
return ans;
}
void graphviz_dump(string filename = "graph.dot") {
ofstream gf; gf.open(filename);
gf << "digraph" << " {\n";
gf << " "; rep(i, 0, n) gf << i << " ;"[i==n-1]; gf << endl;
string notation = " -> ";
rep(u, 0, n) {
for (auto &edge: e[u]) {
int v = edge.v, cap = edge.cap;
if (!cap) continue;
gf << " " << u << notation << v << " ;\n";
}
}
gf << "}\n";
}
void dfs(int u, vector<int> &vis) {
vis[u] = 1;
for (auto &edge: e[u]) {
int v = edge.v;
if (edge.cap && edge.cap > edge.f && !vis[v]) dfs(v, vis);
}
}
void solve() {
int ans = maxflow();
cout << ans << endl;
vector<vector<int>> connect(n);
rep(i, 0, n) connect[i].assign(sz(e[i]), 0);
vector<int> vis(n, 0);
dfs(S, vis);
for (auto &es: e) {
for (auto &edge: es) {
if (edge.cap && vis[edge.u] != vis[edge.v] && edge.v > edge.u) cout << edge.u+1 << " " << edge.v+1 << endl;
}
}
}
};
int32_t main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int n, m; cin >> n >> m;
network g(n, 0, n-1);
rep(i, 0, m) {
int u, v; cin >> u >> v; --u, --v;
g.add_edge(u, v, 1);
g.add_edge(v, u, 1);
}
g.solve();
return 0;
}
No Comments