/* 不要低头,不要放弃,不要气馁,不要慌张 题意: 给一个无向图。现在要求给这个无向图的边加上方向。 定义f(x)为从x点出发能够到达的点的数目。 使得MIN(f(x))最大。 思路: 先tarjan找边双分量,然后从点数最大的边双分量开始dfs。 就酱。 中午老妈刚给我打电话问感冒没,我说没有,晚上就发烧了 gg */ #include<bits/stdc++.h> #define N 400050 using namespace std; int ednum; struct edge{ int nn; int id; edge *next; }; edge edges[N<<1]; edge *adj[N]; struct st{ st(){} st(int a,int b,int c){ s=a;e=b;xu=c; } int s,e,xu; }; vector<st>ans; inline void addedge(int a,int b,int c){ edge *tmp=&edges[ednum++]; tmp->id=b; tmp->nn=c; tmp->next=adj[a]; adj[a]=tmp; } int dfn[N],low[N],id[N],s[N],p,num,t,son[N],nnm[N];//dfn记录dfs时间戳 //low代表当前点到达的最小时间戳,id对点进行分组编号.num是时间戳 //s临时存储数据的手工栈,p栈顶元素的位置,son记录儿子因为无向图记录边都是两个边 void tarjan(int pos){ dfn[pos]=low[pos]=++num; s[++p]=pos; for(edge *it=adj[pos];it;it=it->next){ if(!dfn[it->id]){ son[pos]=it->id; tarjan(it->id); } if(son[it->id]!=pos){ low[pos]=min(low[pos],low[it->id]); } } if(low[pos]==dfn[pos]){ t++; int y; do{ nnm[t]++; y=s[p--]; id[y]=t; }while(y!=pos); } } bool vis[N]; bool vvis[N]; void dfs(int pos){ vis[pos]=1; for(edge *it=adj[pos];it;it=it->next){ if(!vis[it->id]){ son[pos]=it->id; dfs(it->id); } if(son[it->id]!=pos&&!vvis[it->nn]){ vvis[it->nn]=1; ans.push_back(st(pos,it->id,it->nn)); } } } bool cmp(st a,st b){ return a.xu<b.xu; } int main(){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int a,b; scanf("%d%d",&a,&b); addedge(a,b,i); addedge(b,a,i); } tarjan(1); int pos,nnn=-1; for(int i=1;i<=t;i++){ if(nnn<nnm[i]){ pos=i; nnn=nnm[i]; } } printf("%d ",nnn); for(int i=1;i<=n;i++){ if(id[i]==pos){ memset(vis,0,sizeof(vis)); memset(son,0,sizeof(son)); dfs(i); break; } } sort(ans.begin(),ans.end(),cmp); for(int i=0;i<ans.size();i++){ printf("%d %d ",ans[i].e,ans[i].s); } }