【CF 732F】 Tourist Reform(割边+dfs)
题目大意:
n个点m条无向边。
定义
r
i
r_i
ri为从点i出发能遍历到的点的数量。
要求给每个边确定方向,让
m
i
n
(
r
i
)
min(r_i)
min(ri)最大。
输出最大的
m
i
n
(
r
i
)
min(r_i)
min(ri)以及每条边的方向。
考虑对于双连通子图,一定存在方案使每个点都能遍历到图中所有的点。
那么将所有双连通(即无桥)的图锁点,就变成了好几颗树。
对于每个点,内部一定有方法互相到达。点与点之间能且只能确定一个方向。
那么就让所有点都流向最大的点(即缩点前点最多的子图)
那么答案就是这个图。
tarjan跑出来桥,标记好。
从最大的子图中任意一个点开始dfs,把边方向定好即可。
代码如下:
#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <climits>
#include <ctime>
#include <cstring>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<int,int>
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const double eps = 1e-8;
const int maxn = 400123;
const int maxm = 400123;
struct Edge
{
int u,v,next,to;
bool bridge;
} eg[maxm<<1];
bool vis[maxn],in[maxn],out[maxn];
int below[maxn],head[maxn],dfn[maxn],low[maxn];
int tp,tim,pot,mx;
void init()
{
memset(dfn,0,sizeof(dfn));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(head,-1,sizeof(head));
tp = 0;
}
void Add(int u,int v)
{
eg[tp].u = u;
eg[tp].v = v;
eg[tp].next = head[u];
eg[tp].bridge = 0;
eg[tp].to = 0;
head[u] = tp++;
}
void dfs(int u,int pre)
{
dfn[u] = low[u] = ++tim;
//printf("%d %d %d\n",u,dfn[u],low[u]);
for(int i = head[u]; i != -1; i = eg[i].next)
{
int v = eg[i].v;
if(v == pre) continue;
if(!dfn[v])
{
dfs(v,u);
low[u] = min(low[u],low[v]);
if(low[v] > dfn[u])
{
eg[i].bridge = eg[i^1].bridge = 1;
}
}
else low[u] = min(low[u],dfn[v]);
}
}
queue <int> stq;
int bfs(int u)
{
int cnt = 0;
queue <int> q;
q.push(u);
vis[u] = 1;
while(!q.empty())
{
u = q.front();
q.pop();
cnt++;
for(int i = head[u]; i != -1; i = eg[i].next)
{
int v = eg[i].v;
if(vis[v]) continue;
if(eg[i].bridge)
{
stq.push(v);
continue;
}
vis[v] = 1;
q.push(v);
}
}
return cnt;
}
void setb(int u)
{
vis[u] = 1;
for(int i = head[u]; i != -1; i = eg[i].next)
{
int v = eg[i].v;
if(eg[i].to) continue;
if(eg[i].bridge)
{
eg[i].to = -1;
eg[i^1].to = 1;
}
else
{
eg[i].to = 1;
eg[i^1].to = -1;
}
if(!vis[v])
setb(v);
}
vis[u] = 0;
}
int solve(int u)
{
tim = pot = mx = 0;
dfs(u,u);
memset(vis,0,sizeof(vis));
stq.push(u);
while(!stq.empty())
{
int tmp = bfs(stq.front());
if(tmp > mx)
{
mx = tmp;
pot = stq.front();
}
stq.pop();
}
memset(vis,0,sizeof(vis));
setb(pot);
return mx;
}
int main()
{
//fread("");
//fwrite("");
int n,m,u,v;
init();
scanf("%d%d",&n,&m);
for(int i = 0; i < m; ++i)
{
scanf("%d%d",&u,&v);
Add(u,v);
Add(v,u);
}
printf("%d\n",solve(1));
for(int i = 0; i < tp; i += 2)
{
if(eg[i].to == 1) printf("%d %d\n",eg[i].u,eg[i].v);
else printf("%d %d\n",eg[i].v,eg[i].u);
}
return 0;
}