CCF之高速公路(Tarjan演算法,強聯通子圖的求解)
阿新 • • 發佈:2018-12-10
問題描述
試題編號: | 201509-4 |
試題名稱: | 高速公路 |
時間限制: | 1.0s |
記憶體限制: | 256.0MB |
問題描述: |
問題描述 某國有n個城市,為了使得城市間的交通更便利,該國國王打算在城市之間修一些高速公路,由於經費限制,國王打算第一階段先在部分城市之間修一些單向的高速公路。 現在,大臣們幫國王擬了一個修高速公路的計劃。看了計劃後,國王發現,有些城市之間可以通過高速公路直接(不經過其他城市)或間接(經過一個或多個其他城市)到達,而有的卻不能。如果城市A可以通過高速公路到達城市B,而且城市B也可以通過高速公路到達城市A,則這兩個城市被稱為便利城市對。 國王想知道,在大臣們給他的計劃中,有多少個便利城市對。 輸入格式 輸入的第一行包含兩個整數n, m,分別表示城市和單向高速公路的數量。 接下來m行,每行兩個整數a, b,表示城市a有一條單向的高速公路連向城市b。 輸出格式 輸出一行,包含一個整數,表示便利城市對的數量。 樣例輸入 5 5 1 2 2 3 3 4 4 2 3 5 樣例輸出 3 樣例說明 城市間的連線如圖所示。有3個便利城市對,它們分別是(2, 3), (2, 4), (3, 4),請注意(2, 3)和(3, 2)看成同一個便利城市對。 評測用例規模與約定 前30%的評測用例滿足1 ≤ n ≤ 100, 1 ≤ m ≤ 1000; 前60%的評測用例滿足1 ≤ n ≤ 1000, 1 ≤ m ≤ 10000; 所有評測用例滿足1 ≤ n ≤ 10000, 1 ≤ m ≤ 100000。 |
這道題目難度不大,直接套用Tarjan演算法的模板就行,Tarjan演算法的詳細介紹可以參考部落格:
下面是100分的AC程式碼:
#include <cstdio> #include <stack> #include <vector> #include <algorithm> #include <cstring> using namespace std; #define MAX 10005 stack<int> s; vector<int> G[MAX]; int DFN[MAX]; int LOW[MAX]; int vis[MAX]; int instack[MAX]; int res=0; int order=0; void Tarjan(int u) { DFN[u]=LOW[u]=++order; //為結點u設定次序號和Low值 s.push(u);//將結點u壓入到堆疊當中 instack[u]=1; vis[u]=1; for(int j=0;j<G[u].size();j++) //列舉每一條邊 { int v=G[u][j]; if(vis[v]==0) { Tarjan(v); //繼續DFS LOW[u]=min(LOW[u],LOW[v]); } else if(instack[v]) //如果結點v仍然在棧內 { LOW[u]=min(LOW[u],DFN[v]); } } if(DFN[u]==LOW[u])//如果結點u是強聯通分量的根 { int cnt=0; int m; do{ m=s.top(); //將結點m退棧,說明此事結點m是強聯通分量中的一個頂點 instack[m]=0; s.pop(); cnt++; }while(m!=u); if(cnt>1) { res=res+cnt*(cnt-1)/2; } } return; } int main() { int n,m; int a,b; scanf("%d%d",&n,&m); memset(vis,0,sizeof(vis)); memset(G,0,sizeof(G)); memset(DFN,0,sizeof(DFN)); memset(LOW,0,sizeof(LOW)); memset(instack,0,sizeof(instack)); for(int i=0;i<m;i++) { scanf("%d %d",&a,&b); G[a].push_back(b); } for(int i=1;i<=n;i++) { if(vis[i]==0) { vis[i]=1; Tarjan(i); } } printf("%d\n",res); return 0; }