日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【原创】tarjan算法初步(强连通子图缩点)

發(fā)布時間:2025/3/15 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【原创】tarjan算法初步(强连通子图缩点) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

【原創(chuàng)】tarjan算法初步(強(qiáng)連通子圖縮點(diǎn))

tarjan算法的思路不是一般的繞!!(不過既然是求強(qiáng)連通子圖這樣的回路也就可以稍微原諒了。。)

但是研究tarjan之前總得知道強(qiáng)連通分量是什么吧。。

上百度查查:

  有向圖強(qiáng)連通分量:在有向圖G中,如果兩個頂點(diǎn)vi,vj間(vi>vj)有一條從vi到vj的有向路徑,同時還有一條從vj到vi的有向路徑,則稱兩個頂點(diǎn)強(qiáng)連通(strongly connected)。如果有向圖G的每兩個頂點(diǎn)都強(qiáng)連通,稱G是一個強(qiáng)連通圖。有向圖的極大強(qiáng)連通子圖,稱為強(qiáng)連通分量(strongly connected components)。

看不懂。。那么——

?

看這張圖

其中從1可以到2,3,4,5,6;

從2可以到1,3,4,5,6;

從3可以到6;

從4可以到1,2,3,5,6;

從5可以到1,2,3,4,6;

從6哪兒都到不了。

我們發(fā)現(xiàn),{1,2,4,5}兩兩可以互達(dá),我們稱其為原圖的一個強(qiáng)連通子圖,而{3},{6}各自單獨(dú)為原圖的另外兩個強(qiáng)連通子圖。

我們想要通過程序?qū)崿F(xiàn)O(n)求所有強(qiáng)連通子圖,就要用到tarjan算法。

程序代碼如下(tarjan的主要思路寫在程序注釋里,若無法理解請參考另一篇【轉(zhuǎn)載】全網(wǎng)最!詳!細(xì)!tarjan算法講解):

1 // Tarjan有向圖強(qiáng)連通縮點(diǎn) 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<iostream> 6 #include<string> 7 #define MAXV 10010 8 #define MAXE 100010 9 using namespace std; 10 struct tEdge{ 11 int np; 12 tEdge *next; 13 }E[MAXE],*V[MAXV]; 14 int tope=-1; 15 int n,m; 16 int dfn[MAXV],dfstime=0; // dfn[i]表示點(diǎn)i的dfs序 17 int low[MAXV]; // low[i]表示目前點(diǎn)i所能到達(dá)的最小dfs序點(diǎn) 18 int status[MAXV]; // status[i]表示點(diǎn)i的訪問狀態(tài),0=未訪問,1=訪問中,2=訪問完畢 19 int stack[MAXV],tops=-1; 20 int color[MAXV],totc=0; // color[]表示縮點(diǎn)后的塊 21 void addedge(int u,int v){ 22 E[++tope].np=v; 23 E[tope].next=V[u]; 24 V[u]=&E[tope]; 25 } 26 void tarjan(int now){ 27 stack[++tops]=now; // 進(jìn)棧 28 low[now]=dfn[now]=++dfstime; // 初始化dfs序 29 status[now]=1; // 訪問中(在棧中) 30 for(tEdge *ne=V[now];ne;ne=ne->next){ 31 if(status[ne->np]==0){ // 未訪問(沒有進(jìn)過棧) 32 tarjan(ne->np); // dfs往下進(jìn)行遞歸訪問 33 low[now]=min(low[now],low[ne->np]); 34 // 由于now可達(dá)ne->np,故ne->np可達(dá)的最小dfs序點(diǎn)從now也可達(dá) 35 } 36 else if(status[ne->np]==1){ // 回邊,發(fā)現(xiàn)ne->np為棧中元素 37 low[now]=min(low[now],dfn[ne->np]); 38 // 若ne->np的dfs序比原來now可達(dá)的最小dfs序還小則更新 39 } 40 } 41 if(low[now]==dfn[now]){ 42 // now到達(dá)的最小dfs序為自己dfs序 43 // 即now不包含在最小dfs序更小的縮點(diǎn)中 44 // 而棧中now以后的節(jié)點(diǎn)若不能到達(dá)now則早已出棧(FILO) 45 totc++; // 申請新顏色(一種顏色代表一個縮點(diǎn)) 46 while(stack[tops+1]!=now){ // 棧中所有在now之后的節(jié)點(diǎn)都在該縮點(diǎn)內(nèi) 47 status[stack[tops]]=2; // 訪問完畢(已出棧) 48 color[stack[tops--]]=totc; // 為節(jié)點(diǎn)染色 49 } 50 } 51 } 52 int main(){ 53 memset(dfn,0,sizeof(dfn)); 54 memset(low,0,sizeof(low)); 55 memset(status,0,sizeof(status)); 56 scanf("%d%d",&n,&m); 57 for(int i=1;i<=m;i++){ 58 int u,v; 59 scanf("%d%d",&u,&v); 60 addedge(u,v); 61 } 62 for(int i=1;i<=n;i++) 63 if(status[i]==0) 64 tarjan(i); // 圖不連通時必須保證每個點(diǎn)都處理到 65 for(int i=1;i<=n;i++) 66 printf("Point %d colored %d\n",i,color[i]); // 輸出所屬強(qiáng)連通塊編號 67 return 0; 68 }

測試數(shù)據(jù):

6 8 1 2 2 3 3 6 5 6 1 4 5 1 4 5 2 5

運(yùn)行結(jié)果:

Point 1 colored 3 Point 2 colored 3 Point 3 colored 2 Point 4 colored 3 Point 5 colored 3 Point 6 colored 1

即color[1]={6},color[2]={3},color[3]={1,2,4,5}為原圖的3個強(qiáng)連通子圖的縮點(diǎn)。

轉(zhuǎn)載于:https://www.cnblogs.com/darkleafin/p/7219537.html

總結(jié)

以上是生活随笔為你收集整理的【原创】tarjan算法初步(强连通子图缩点)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。