CSP 強聯通分量和Kosaraju實現

2021-10-05 02:42:28 字數 3431 閱讀 7501

題目簡述

題目重述

思路概述

題目原始碼

強聯通分量是圖論的常見概念之一,強聯通問題也是圖論演算法題中常見的題目。但由於學習強聯通分量問題需要有一定的知識基礎,我們分成三個部分講解。

void

dfs(

int st)

vec_back.

push_back

(st)

;//後序序列

}

強聯通分量的基礎定義在此我們也做以贅述,如果你忘記了可以讀一遍,如果還清楚可以直接跳過進入具體演算法。

強聯通是圖上的一種性質:如果在乙個圖內,任意兩點a,b之間,都有路徑a–>b&&b–>a則認為該圖是強聯通的。

如果在乙個不是強聯通的圖中,有某些部分滿足強聯通的特性,則這些部分成為乙個圖的強聯通分量(又稱強聯通子圖)簡稱scc。

為了在乙個圖中找到所有的scc,並且標識出來,引入演算法kosaraju來進行實現。

kosaraju演算法的實現過程如下:

1、原圖按照點公升序求dfs後序,進而獲得逆後序。

2、對應原圖求出乙個反圖,在反圖上,按照逆後序的點序,dfs整個圖。每次遍歷到邊界時,說明前面的點屬於同乙個scc。

(核心思想:將原圖的逆後序作為乙個拓撲序列,按照這個順序對反圖做dfs)

具體實現可以看文末源**。

大學班級選班長,n 個同學均可以發表意見 若意見為 a b 則表示 a 認為 b 合適,意見具有傳遞性,即 a 認為 b 合適,b 認為 c 合適,則 a 也認為 c 合適 勤勞的 tt 收集了m條意見,想要知道最高票數,並給出乙份候選人名單,即所有得票最多的同學,你能幫幫他嗎?

本題有多組資料。第一行 t 表示資料組數。每組資料開始有兩個整數 n 和 m (2 <= n <= 5000, 0 2

4 33 2

2 02 1

3 31 0

2 10 2

對於每組資料,第一行輸出 「case x: 」,x 表示資料的編號,從1開始,緊跟著是最高的票數。 接下來一行輸出得票最多的同學的編號,用空格隔開,不忽略行末空格!

輸出樣例:

case 1: 2

0 1case 2: 2

0 1 2

同樣是經典的傳遞問題,有a b&&b c–>a c。如果a b,含義是a支援b。求出支持者最多的點和支援的點數(即求出路徑入度最大的點)

路徑入度:乙個點通過直接或者間接可以到a,則a的路徑入度+1.

在乙個隨機圖中,一定會出現很多scc(每兩點間互相支援),在這種情況下scc為每個成員都會提供scc點數-1的路徑入度。因此我們可以使用上述的演算法,求出圖中所有的scc。但是路徑入度還不止如此,因為在scc求解完成後,整個圖變成如下的形態:

按照這個原則,我們可以通過scc後,進行縮點縮邊,得到乙個如上圖所示的有向無環圖,再利用該圖進行dfs,找到路徑入度最大的scc,該scc就是所求的點集。

注意點:在scc形成的有向無環圖中,並不需要dfs每個點。可以輕易證明的是,路徑入度最大的scc一定是出度為0的scc,只需要dfs這些scc並比較大小即可。

#include

#include

#include

#include

#include

using

namespace std;

const

int m=

5e4+10;

const

int inf=

1e9;

int head[m]

,vis[m]

,head_minus[m]

,color[m]

,col_num[m]

,dis[m]

,col_dis[m]

;int scc_head[m]

;int point_cnt,edge_cnt,number1=

0,number2=

0,group,color_cnt=

0,mytot=0;

vector<

int> vec;

setint,

int>

> st;

struct edgeedges[m]

,revr[m]

,myedge[m]

,*ped;

void

add(

int x,

int y,

int z)

else

if(z==2)

else

(*cnt)++;

ped[

*cnt]

.to=y;

ped[

*cnt]

.next=head_flag[x]

,head_flag[x]

=*cnt;

}void

init()

}//正dfs獲得逆反序

void

dfs1

(int st)

vec.

push_back

(st);}

//逆反序dfs生成scc

void

dfs2

(int st)}}

//生成新圖中dfs

intdfs_scc

(int st)

return ans+col_num[st];}

void

kosaraju()

}//縮點

for(

int i=

0;i++i)}}

//縮點加邊

for(

auto it=st.

begin()

;it!=st.

end(

);it++

)//找到最大值

int max_num=-1

;for

(int i=

1;i<=color_cnt;i++)}

printf

("%d\n"

,max_num-1)

;//只要col所在的scc值等於max_num,就輸出

bool flag=

true

;for

(int i=

0;i++i)

else

printf

(" %d"

,i);}}

}int

main()

printf

("case %d: "

,data)

;kosaraju()

;printf

("\n");

}return0;

}

強聯通分量

有向圖中 u可達 v不一定意味著v可達 u.相互可達則屬於同乙個強連通分量 strongly connected component,scc 最關鍵通用部分 強連通分量一定是圖的深搜樹的乙個子樹。1.演算法思路 基本思路 這個演算法可以說是最容易理解,最通用的演算法,其比較關鍵的部分是同時應用了原圖...

強聯通分量

include include include include include include include include using namespace std struct edge vectora 80005 b 80005 node 80005 int he 80005 int n,m,...

強聯通分量

2020 10 31 內容來自oi wiki和yu xuan 的講課 強聯通分量 個人理解 tarjan 演算法是由棧來實現的 dfn u dfs序 low u 以u為根的子樹,最小的dfs序那麼會出現 3 中情況 void tarjan int u else if vis v 1 low u mi...