# 【题解】新型城市化 HAOI2017 网络流 二分图最大匹配 强连通分量

### Solution

“在两个城市之间建立贸易关系”即删除这两个点之间的边。

### Code

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <utility>

using namespace std;
typedef pair<int,int> pii;
const int MAXN = 10010;
const int MAXM = 150010;
const int MAXV = 100010;
const int MAXE = 1000010;
const int INF = 0x3f3f3f3f;
int _w;

int n, m, uu[MAXM], vv[MAXM];

namespace G {
void init() {
eid = 0;
}
void adde( int u, int v ) {
}
}

namespace Dinic {
struct Edge {
int u, v, c, f;
Edge() {}
Edge( int u, int v, int c, int f ):
u(u), v(v), c(c), f(f) {}
};

int n, m, s, t;
Edge edge[MAXE<<1];
int dis[MAXV], cur[MAXV];
queue<int> q;

void init( int _n ) {
n = _n, m = 0;
for( int i = 0; i < n; ++i )
}
int adde( int u, int v, int c ) {
int eid = m;
edge[m] = Edge(u, v, c, 0);
edge[m] = Edge(v, u, 0, 0);
return eid;
}
bool bfs() {
for( int i = 0; i < n; ++i )
dis[i] = INF;
dis[s] = 0, q.push(s);
while( !q.empty() ) {
int u = q.front(); q.pop();
for( int i = head[u]; ~i; i = nxt[i] ) {
Edge &e = edge[i];
if( e.c > e.f && dis[e.v] == INF ) {
dis[e.v] = dis[u] + 1;
q.push(e.v);
}
}
}
return dis[t] != INF;
}
int dfs( int u, int res ) {
if( u == t || !res ) return res;
int flow = 0;
for( int &i = cur[u]; ~i; i = nxt[i] ) {
Edge &e = edge[i];
if( e.c > e.f && dis[e.v] == dis[u] + 1 ) {
int f = dfs( e.v, min(res, e.c-e.f) );
flow += f, res -= f;
e.f += f, edge[i^1].f -= f;
if( !res ) break;
}
}
return flow;
}
int solve( int _s, int _t ) {
s = _s, t = _t;
int flow = 0;
while( bfs() ) {
for( int i = 0; i < n; ++i )
flow += dfs(s, INF);
}
return flow;
}
}

namespace Bipartite {
int color[MAXN], eid[MAXM];
queue<int> q;

void bfs( int s ) {
using namespace G;

color[s] = 0, q.push(s);
while( !q.empty() ) {
int u = q.front(); q.pop();
for( int i = head[u]; ~i; i = nxt[i] ) {
int v = to[i];
if( color[v] == -1 ) {
color[v] = !color[u];
q.push(v);
}
}
}
}
void bipartite() {
for( int i = 1; i <= n; ++i )
color[i] = -1;
for( int i = 1; i <= n; ++i )
if( color[i] == -1 )
bfs(i);
int s = 0, t = n+1;
Dinic::init(t+1);
for( int i = 1; i <= n; ++i )
if( color[i] ) Dinic::adde(s, i, 1);
for( int i = 0; i < m; ++i )
if( color[uu[i]] )
eid[i] = Dinic::adde( uu[i], vv[i], 1 );
else
eid[i] = Dinic::adde( vv[i], uu[i], 1 );
Dinic::solve(s, t);
}
}
using Bipartite::bipartite;

namespace Tarjan {
using namespace Dinic;

int dfn[MAXV], low[MAXV], scc[MAXV], dfnc, sccc;
stack<int> stk;

void dfs( int u ) {
dfn[u] = low[u] = ++dfnc;
stk.push(u);
for( int i = head[u]; ~i; i = nxt[i] ) {
Edge &e = edge[i];
if( e.c == e.f ) continue;
int v = e.v;
if( !dfn[v] ) {
dfs(v);
low[u] = min( low[u], low[v] );
} else if( !scc[v] ) {
low[u] = min( low[u], dfn[v] );
}
}
if( low[u] == dfn[u] ) {
++sccc;
while(1) {
int o = stk.top(); stk.pop();
scc[o] = sccc;
if( o == u ) break;
}
}
}
void tarjan() {
dfnc = sccc = 0;
for( int i = 0; i < Dinic::n; ++i )
if( !dfn[i] ) dfs(i);
}
}
using Tarjan::tarjan;

namespace Solve {
vector<pii> ans;
void solve() {
using Dinic::Edge;
using Dinic::edge;
using Tarjan::scc;
using Bipartite::eid;

for( int i = 0; i < m; ++i ) {
Edge &e = edge[eid[i]];
if( e.c != e.f ) continue;
int u = e.u, v = e.v;
if( u > v ) swap(u, v);
if( scc[u] == scc[v] ) continue;
ans.push_back( pii(u, v) );
}
sort(ans.begin(), ans.end());
printf( "%lu\n", ans.size() );
for( int i = 0; i < (int)ans.size(); ++i )
printf( "%d %d\n", ans[i].first, ans[i].second );
}
}
using Solve::solve;

int main() {
_w = scanf( "%d%d", &n, &m );
G::init();
for( int i = 0; i < m; ++i ) {
_w = scanf( "%d%d", uu+i, vv+i );
}