ccf 高速公路

2021-07-10 22:46:17 字數 2950 閱讀 8223

問題描述

某國有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。

解題關鍵:

求圖中的強連通分量,對於每乙個連通分量,節點對數為 n * ( n - 1) /2 (n > 1).

有向圖強連通分量:

在有向圖g中,如果兩個頂點vi,vj間有一條從vi到vj的有向路徑,同時還有一條從vj到vi的有向路徑,則稱兩個頂點強連通。如果有向圖g的

每兩個頂點都強連通,稱g是乙個強連通圖。有向圖的極大強連通子圖,稱為強連通分量。

求強連通分量的演算法有三種:

首先對圖g進行一次dfs,計算出各頂點完成搜尋的時間f;然後計算圖的逆向圖

gt,對逆向圖進行dfs,不過此次搜尋時頂點的訪問次序不是按

照頂點標號的大小,而是按照各頂點f值由大到小的順序;逆向圖dfs得到的森林即對應連通區域

#include #include #include using namespace std;

#define n 10005

vector edge[n], redge[n];//存放圖、反向圖

vector time; //記錄每個節點的離開時間

int vis[n];//標記節點是否被訪問過

int belong[n], num[n]; //belong:每個節點所屬的連通分量 num:統計每個連通分量中節點的個數

int id; //連通分量的個數

void dfs1(int u) //記錄dfs後各結點的結束時間

}time.push_back(u);

}void dfs2(int u) //從time的尾部取出節點後, 對反向圖進行dfs

}}int main()

//第一遍dfs

memset(vis, 0, sizeof(vis));

for(int i = 1; i <= n; i++)

//第二遍dfs

memset(vis, 0, sizeof(vis));

memset(num, 0, sizeof(num));

id = 0;

for(int i = time.size() - 1; i >= 0; i--)

}//統計強連通的節點對數

int sum = 0;

for(int i = 1; i <= id; i++)

cout<2、tarjan演算法

tarjan演算法

基於遞迴實現的深度優先搜尋,在搜尋過程中將頂點不斷壓入堆疊中,並在回溯時判斷堆疊中頂點是否在同一聯通分支。

函式借助兩個輔助陣列dfn

和low,其中dfn

[u]為

頂點u搜尋的次序編號,l

ow[u]為頂點u以及子樹

能回溯到的最早的棧中

頂點的次序編號。

當dfn

[u]=l

ow[u]時,則

彈出棧中頂點並構成乙個連通分支。

#include #include #include using namespace std;

#define n 10005

vector edge[n];//圖

int dfn[n]; //節點u搜尋的次序編號(時間戳)

int low[n]; //節點u或u的子樹能夠追溯到的最早的棧中節點的次序編號

int belong[n]; //每個節點所屬的連通分量

int num[n]; //統計每個連通分量中節點的個數

int vis[n]; //標記節點是否被訪問過

stack st; //存放訪問過的節點

int instack[n]; //標記節點是否在棧中

int index = 0; //當前次序編號

int id = 0; //連通分量的個數

void dfs (int u)

else if(instack[v] && low[u] > low[v])

}if(low[u] == dfn[u])

while( u != v);

}}int main()

for(int i = 1; i <= n; i++)

int sum = 0;

for(int i = 1; i <= id; i++)

cout<

CCF高速公路

新學了tarjan演算法,今天中午之前還沒聽過,用dfs硬寫加了點優化得了70,對路的演算法還是給力,直接滿分。回頭整理一篇關於強連通分量的部落格,另外這次往後就慢慢全用c 了。include include include include define maxsize 10005 using na...

ccf 高速公路 100

試題編號 201509 4 試題名稱 高速公路 時間限制 1.0s 記憶體限制 256.0mb 問題描述 問題描述 某國有n個城市,為了使得城市間的交通更便利,該國國王打算在城市之間修一些高速公路,由於經費限制,國王打算第一階段先在部分城市之間修一些單向的高速公路。現在,大臣們幫國王擬了乙個修高速公...

CCF 201509 4 高速公路

問題描述 試題編號 201509 4 試題名稱 高速公路 時間限制 1.0s 記憶體限制 256.0mb 問題描述 問題描述 某國有n個城市,為了使得城市間的交通更便利,該國國王打算在城市之間修一些高速公路,由於經費限制,國王打算第一階段先在部分城市之間修一些單向的高速公路。現在,大臣們幫國王擬了乙...