CodeForces 732F. Tourist Reform 邊雙聯通分量
阿新 • • 發佈:2018-12-11
題目連結:http://codeforces.com/problemset/problem/732/F
題意:
給你一個無向連通圖,要你把這個圖的邊變成有向邊,使得每個點能到達的點數最大,按順序輸出每條邊的連向。
做法:
有點繞吧聽著,每個點都能達到的點最大的話,最好的就是相互都能到達,那麼我們自然的就想到強連通分量,一個強聯通分量內的點可以相互到達,當然這道題因為是無向圖,所以就是邊雙連通分量了,那麼對於不同分量的點呢?因為我們要使得每個點都能到的點最大,如果我們把大的分量的點指向小的,那麼很明顯,最大的就是那個小的了,所以我們就要把邊的朝向都指向那個最大的強連通分量。這裡有個小優化,如果搜尋的時候在一個強連通分量內的話,那麼就正常朝向,否則取反向邊(因為我們要讓所有的點都能指向那個最大的分量)
#include<bits/stdc++.h> using namespace std; const int inf=0x3f3f3f3f; const int maxn=400005; struct node{ int from,to,next; }e[maxn<<1]; stack<int> sa; int now,head[maxn],bccsum[maxn],bccnum,mark[maxn]; int dfn[maxn],low[maxn],belong[maxn],n,m,cnt,vis[maxn<<1]; bool las[maxn]; void add(int u,int v){ e[now].from=u,e[now].to=v; e[now].next=head[u],head[u]=now++; } void tarjan(int x,int fa){ dfn[x]=low[x]=++cnt; sa.push(x); for(int i=head[x];~i;i=e[i].next){ int v=e[i].to; if(v==fa) continue; if(!dfn[v]){ tarjan(v,x); low[x]=min(low[x],low[v]); } else if(!belong[v]) low[x]=min(low[x],low[v]); } if(dfn[x]==low[x]){ bccnum++; bccsum[bccnum]=0; while(1){ int u=sa.top();sa.pop(); belong[u]=bccnum; bccsum[bccnum]++; if(u==x) break; } } } void dfs(int now){ las[now]=1; for(int i=head[now];~i;i=e[i].next){ int v=e[i].to; if(vis[i]!=0) continue; if(belong[v]==belong[now]){ vis[i]=1; vis[i^1]=-1; } else vis[i^1]=1,vis[i]=-1; if(!las[v]) dfs(v); } } void init(){ memset(head,-1,sizeof(head)); now=0; cnt=0; bccnum=0; memset(mark,0,sizeof(mark)); memset(las,0,sizeof(las)); memset(dfn,0,sizeof(dfn)); memset(vis,0,sizeof(vis)); } int main(){ while(~scanf("%d%d",&n,&m)){ if(n==0&&m==0) break; int u,v; init(); for(int i=1;i<=m;i++){ scanf("%d%d",&u,&v); add(u,v); add(v,u); } tarjan(1,1); int root=1; for(int i=2;i<=n;i++){ if(bccsum[belong[i]]>bccsum[belong[root]]){ root=i; } } dfs(root); printf("%d\n",bccsum[belong[root]]); for(int i=0;i<now;i+=2){ if(vis[i]==1) printf("%d %d\n",e[i].from,e[i].to); else printf("%d %d\n",e[i^1].from,e[i^1].to); } } return 0; }