150904 高速公路 ccf

參考html

Kosarajuc++

http://www.javashuo.com/article/p-cmjtpfng-cx.html算法

tarjanide

https://blog.csdn.net/qq_34374664/article/details/77488976spa

思路.net

求迴路也就是求圖的強連通份量code

共有兩種算法:Kosaraju與tarjan,其中Kosaraju算法較易理解但須要兩次dfs,tarjan算法較難理解但只需dfs一次。htm

兩種算法的詳解見參考。blog

概述:ci

Kosaraju

一、對圖的反向圖進行一次逆後序dfs遍歷

二、按照逆後序遍歷獲得的棧中點的出棧順序對原圖進行dfs遍歷,每一次遍歷訪問到的點就屬於一個強連通份量。

tarjan

 1 /*
 2 dfn爲訪問序號(時間戳)
 3 low爲當前節點及其子樹中結點最小的訪問序號,相似並查集
 4 */
 5 void tarjan(int u){
 6 
 7   DFN[u]=Low[u]=++Index // 爲節點u設定次序編號和Low初值
 8 
 9   Stack.push(u)   // 將節點u壓入棧中
10 
11   for each (u, v) in E // 枚舉每一條邊
12     {
13             if (v is not visted) // 若是節點v未被訪問過
14 
15     {
16                 tarjan(v) // 繼續向下找
17                 Low[u] = min(Low[u], Low[v])
18             }    
19 
20     else if (v in S) // 若是節點u還在棧內
21 
22     {   Low[u] = min(Low[u], DFN[v])   }
23     }
24 
25   if (DFN[u] == Low[u]) // 若是節點u是強連通份量的根
26    {
27            repeat 
28        
29            v = S.pop  // 將v退棧,爲該強連通份量中一個頂點
30 
31        print v
32 
33        until (u== v)    
34    }
35 
36 }                    
tarjan僞代碼

實現

Kosaraju

 1 //Kosaraju
 2 #include<bits/stdc++.h>
 3 
 4 using namespace std;
 5 
 6 #define MAXN 10005
 7 
 8 vector<int> Map1[MAXN];
 9 vector<int> Map2[MAXN];
10 stack<int> sta; 
11 int vis[MAXN];
12 long long int ans=0,num=0;
13 int n,m;
14 
15 int size,v;
16 void dfs2(int s){
17     
18     for(int i=0;i<Map2[s].size();i++){
19         v=Map2[s][i];
20         if(vis[v]==0){
21             vis[v]=1;
22             dfs2(v);    
23         }
24     }
25     sta.push(s);
26 }
27 
28 void dfs1(int s){
29     for(int i=0;i<Map1[s].size();i++){
30         v=Map1[s][i];
31         if(vis[v]==0){
32             //cout<<v<<' ';
33             vis[v]=1;
34             num++;
35             dfs1(v);
36         }
37     }
38 }
39 
40 long long int C(int x){
41     if(x<=1){
42         return 0;
43     }
44     else{
45         long long int a=1;
46         for(int i=x;i>x-2;i--){
47             a*=i;
48         }
49         return a/2;
50     }
51 }
52 
53 int main(){
54     cin>>n>>m;
55     int a,b;
56     for(int i=0;i<m;i++){
57         cin>>a>>b;
58         Map1[a].push_back(b);
59         Map2[b].push_back(a);
60     }
61     
62     memset(vis,0,sizeof(vis));
63     for(int i=0;i<=n;i++){
64         if(vis[i]==0){
65             vis[i]=1;
66             dfs2(i);
67         }
68     }
69     
70     memset(vis,0,sizeof(vis));
71     int v;
72     while(!sta.empty()){
73         v=sta.top();
74         sta.pop();
75         
76         if(vis[v]==0){
77             //cout<<v<<' ';
78             vis[v]=1;
79             num=1;
80             dfs1(v);
81             //cout<<num<<endl;
82             ans+=C(num);
83         }
84     }
85 
86     cout<<ans;
87     
88     return 0;
89 }
View Code

tarjan

 1 //tarjan
 2 
 3 #include<bits/stdc++.h>
 4 
 5 using namespace std;
 6 
 7 #define MAXN 10005
 8 
 9 vector<int> Map[MAXN];
10 stack<int> sta;
11 int vis[MAXN];
12 int dfn[MAXN];
13 int low[MAXN];
14 int insta[MAXN];
15 long long int num=0,ans=0;
16 int n,m,index;
17 
18 long long int C(int x){
19     if(x<=1){
20         return 0;
21     }
22     else{
23         long long int a=1;
24         for(int i=x;i>x-2;i--){
25             a*=i;
26         }
27         return a/2;
28     }
29 }
30 
31 void tarjan(int u)
32 {
33     index++;
34     dfn[u]=low[u]=index;
35     vis[u]=1;
36     sta.push(u);
37     insta[u]=1;
38     int  size=Map[u].size();
39     for(int i=0;i<size;i++){
40         int v=Map[u][i];
41         if(vis[v]==0){
42             tarjan(v);
43             low[u]=min(low[u],low[v]);
44         }
45         else if(insta[v]==1){
46             low[u]=min(low[u],dfn[v]);
47         }
48     }
49     num=0;
50     if(dfn[u]==low[u]){
51         int v;
52         do{
53             v=sta.top();
54             //cout<<v<<' ';
55             sta.pop();
56             insta[v]=0;
57             num++;
58         }while(v!=u);
59         //cout<<endl;
60     }
61     ans+=C(num);
62 }
63 
64 int main(){
65     cin>>n>>m;
66     int a,b;
67     for(int i=0;i<m;i++){
68         cin>>a>>b;
69         Map[a].push_back(b);
70     }
71     memset(vis,0,sizeof(vis));
72     memset(insta,0,sizeof(insta));
73     index=0;
74     for(int i=1;i<=n;i++){
75         if(vis[i]==0){            
76             tarjan(i);
77         }
78     }
79     cout<<ans;
80     
81     return 0;
82 }
View Code

題目

問題描述
 
  某國有 n個城市,爲了使得城市間的交通更便利,該國國王打算在城市之間修一些高速公路,因爲經費限制,國王打算第一階段先在部分城市之間修一些單向的高速公路。
  如今,大臣們幫國王擬了一個修高速公路的計劃。看了計劃後,國王發現,有些城市之間能夠經過高速公路直接(不通過其餘城市)或間接(通過一個或多個其餘城市)到達,而有的卻不能。若是城市A能夠經過高速公路到達城市B,並且城市B也能夠經過高速公路到達城市A,則這兩個城市被稱爲便利城市對。
  國王想知道,在大臣們給他的計劃中,有多少個便利城市對。
 
輸入格式
 
  輸入的第一行包含兩個整數 nm,分別表示城市和單向高速公路的數量。
  接下來 m行,每行兩個整數 ab,表示城市 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。
相關文章
相關標籤/搜索