题目链接:http://codeforces.com/problemset/problem/732/F
题意:
给出一个有n个点m条边的无向图,保证联通,现在要求将所有边给定一个方向使其变成有向图,设f(x)为点x能到达的点的个数,要求使最小的f(x)最大,并输出方案。
思路:
tarjan一下,答案肯定是强连通分量里点最多的一个分量,而同一个强连通里的点成环,其他分量都指向这个最大点个数的分量。
退役了,偶尔刷一下题...
#include <bits/stdc++.h>
using namespace std;
const int N = 4e5 + ;
struct Edge {
int next, to;
}edge[N << ];
int head[N], tot;
int low[N], dfn[N], st[N], block[N];
int top, ord, scc;
bool instack[N];
int _u[N], _v[N];
int Max, pos;
map <int, int> mp[N];
bool vis[N]; void init() {
memset(head, -, sizeof(head));
} void addedge(int u, int v) {
edge[tot].next = head[u];
edge[tot].to = v;
head[u] = tot++;
} void tarjan(int u, int par) {
low[u] = dfn[u] = ++ord;
st[++top] = u;
instack[u] = true;
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to;
if(v == par)
continue;
if(!dfn[v]) {
tarjan(v, u);
low[u] = min(low[u], low[v]);
} else if(instack[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if(low[u] == dfn[u]) {
int v, cnt = ;
++scc;
do {
v = st[top--];
instack[v] = false;
block[v] = scc;
++cnt;
} while(u != v);
if(cnt > Max) {
Max = cnt, pos = v;
}
}
} void dfs(int u, int p) {
vis[u] = true;
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to;
if(v == p || mp[u][v] || mp[v][u]) {
continue;
} else if(vis[v]) {
mp[u][v] = ;
continue;
}
mp[u][v] = ;
dfs(v, u);
}
} int main()
{
init();
int n, m;
scanf("%d %d", &n, &m);
for(int i = ; i <= m; ++i) {
scanf("%d %d", _u + i, _v + i);
addedge(_u[i], _v[i]);
addedge(_v[i], _u[i]);
}
tarjan(, -);
dfs(pos, -);
printf("%d\n", Max);
for(int i = ; i <= m; ++i) {
if(block[_u[i]] != block[_v[i]]) {
if(!mp[_u[i]][_v[i]]) {
printf("%d %d\n", _u[i], _v[i]);
} else {
printf("%d %d\n", _v[i], _u[i]);
}
} else {
if(mp[_u[i]][_v[i]]) {
printf("%d %d\n", _u[i], _v[i]);
} else {
printf("%d %d\n", _v[i], _u[i]);
}
}
}
return ;
}