1. 程式人生 > >201509-4 高速公路 tarjan強連通分量演算法 O(V+E)

201509-4 高速公路 tarjan強連通分量演算法 O(V+E)

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<vector>
#include<string>
#include<limits.h>
#include<cmath>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<functional> #define iter(i,start,end) for(int (i)=(start);(i)<(end);(i)++) using namespace std; const int nmax=10000+5; int n,m; //n城市個數\in[1,10000] m單向高速公路個數\in[1,100000] vector<int>g[nmax]; int groupnum,time,ans; //groupnum強連通分量的數量(從1開始計數 time時間 ans強連通分量中點對的數量 bool onstack[nmax]; //是否在棧內
int group[nmax],low[nmax],dfn[nmax],member[nmax]; //low記錄該點最早能回溯到的地方 dfn各點的時間戳 member[i]記錄第i組有幾個點【其實這個陣列可以通過邊遍歷邊記錄ans省下來】 stack<int> s; void init(); void tarjan(int cur); int main() { //freopen("201509-4.txt","r",stdin); while(scanf("%d %d",&n,&m)==2) { init(); while
(!s.empty()) s.pop(); time=1; iter(i,0,n){ if(!dfn[i]) tarjan(i); } iter(i,0,n) member[group[i]]++; sort(member+1,member+groupnum+1,greater<int>()); //【記錄下是不是這麼寫的】 iter(i,1,groupnum+1){ if(member[i]>1) ans+=member[i]*(member[i]-1)/2; } cout<<ans; } return 0; } void tarjan(int cur){ low[cur]=dfn[cur]=time++; onstack[cur]=true; s.push(cur); //【記錄】這幾個stl的函式 iter(i,0,g[cur].size()){ int to=g[cur][i]; if(!dfn[to]){ //如果遍歷過就不要進去了 不然dfn和low陣列都會變化的 tarjan(to); if(low[to]<low[cur]) //或者直接用Min(low[to],low[cur])代替 low[cur]=low[to]; } else{ if(onstack[to] && dfn[to] < low[cur]) //在這裡wa了半天 忘了判斷dfn[to] < low[cur]了 low[cur]=dfn[to]; //如果直接用Min(low[cur],dfn[to])代替 就不會wa這麼久了...吃了沒讀書的虧 } } if(low[cur]==dfn[cur]) //小環套大環也不怕 { int tmp=-1,cnt=0; //tmp賦為-1是因為節點編號從0開始的 while(tmp!=cur){ tmp=s.top(); s.pop(); group[tmp]=groupnum; onstack[tmp]=false; cnt++; } groupnum++; if(cnt>1) ans+=cnt*(cnt-1)/2; //如果強連通分量只由一個數組成,也不存在什麼點對之說了 } } void init(){ memset(g,0,sizeof(g)); int u,v; iter(i,0,m){ cin>>u>>v; g[u-1].push_back(v-1); } groupnum=1,time=0,ans=0; memset(onstack,0,sizeof(onstack)); memset(group,0,sizeof(group)); //0表示還沒分組 memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(member, 0, sizeof(cout)); }