先用边-双连通的方式缩点,然后就能发现包含城市最多的那个点就是答案。点内肯定有环,直接连就行了,剩下的割边都指向城市最多的那个点。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int MAXN= 4e5+5;
vector<PII> G[MAXN];
vector<PII> edges;
int dfs_clock, tmp;
PII ans;
int pre[MAXN], iscut[MAXN], vis[MAXN];
int dfs1(int u, int fa) {
int lowu = pre[u] = ++dfs_clock;
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i].first, id = G[u][i].second;
if(v == fa) continue;
if(!pre[v]) {
int lowv = dfs1(v, u);
lowu = min(lowv, lowu);
if(lowv > pre[u]) {
iscut[id] = 1;
}
}
else if(pre[v] < pre[u]) lowu = min(lowu, pre[v]);
}
return lowu;
}
void dfs2(int u, int fa) {
if(!pre[u]) tmp++;
pre[u] = 1;
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i].first, id = G[u][i].second;
if(v==fa || iscut[id]) continue;
if(!vis[id]) {
vis[id] = 1;
edges[id] = make_pair(u, v);
dfs2(v, u);
}
}
}
void dfs3(int u) {
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i].first, id = G[u][i].second;
if(!vis[id]) {
vis[id] = 1;
if(iscut[id]) {
edges[id] = make_pair(v, u);
}
dfs3(v);
}
}
}
int main() {
memset(pre, 0, sizeof(pre));
memset(iscut, 0, sizeof(iscut));
int n, m;
cin >> n >> m;
edges.resize(m+1);
for(int i = 1; i <= m; i++) {
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(make_pair(v, i));
G[v].push_back(make_pair(u, i));
}
dfs_clock = 0;
dfs1(1, -1);
memset(pre, 0, sizeof(pre));
memset(vis, 0, sizeof(vis));
ans.first = 0;
for(int i = 1; i <= n; i++) if(!pre[i]) {
tmp = 0;
dfs2(i, -1);
if(tmp > ans.first) {
ans.first = tmp;
ans.second = i;
}
}
memset(vis, 0, sizeof(vis));
dfs3(ans.second);
printf("%d\n", ans.first);
for(int i = 1; i <= m; i++) printf("%d %d\n", edges[i].first, edges[i].second);
return 0;
}