題目簡述
題目重述
思路概述
題目原始碼
強聯通分量是圖論的常見概念之一,強聯通問題也是圖論演算法題中常見的題目。但由於學習強聯通分量問題需要有一定的知識基礎,我們分成三個部分講解。
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同樣是經典的傳遞問題,有a b&&b c–>a c。如果a b,含義是a支援b。求出支持者最多的點和支援的點數(即求出路徑入度最大的點)0 1case 2: 2
0 1 2
路徑入度:乙個點通過直接或者間接可以到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...