HDU4324(强连通的Tarjan算法)
算法思路:
??
????? ?這個(gè)算法思路不難理解,任何一個(gè)強(qiáng)連通分量,必定是對原圖的深度優(yōu)先搜索樹的子樹。
?????? 那么其實(shí),我們只要確定每個(gè)強(qiáng)連通分量的子樹的根,然后根據(jù)這些根從樹的最低層開始,一個(gè)一個(gè)的拿出強(qiáng)連通分量即可。那么眼下的問題就只
剩下如何確定強(qiáng)連通分量的根和如何從最低層開始拿出強(qiáng)連通分量了。
?????
?????? 那么如何確定強(qiáng)連通分量的根,在這里我們維護(hù)兩個(gè)數(shù)組,一個(gè)是indx[1..n],一個(gè)是mlik[1..n],其中indx[i]表示頂點(diǎn)i開始訪問時(shí)間,mlik[i]為與
頂點(diǎn)i鄰接的頂點(diǎn),未刪除頂點(diǎn)j的mlik[j]和mlik[i]的最小值(mlik[i]初始化為indx[i])。這樣,在一次深搜的回溯過程中,如果發(fā)現(xiàn)mlik[i]==indx[i]那么,
當(dāng)前頂點(diǎn)就是一個(gè)強(qiáng)連通分量的根,為什么呢?因?yàn)槿绻皇菑?qiáng)連通分量的跟,那么它一定是屬于另一個(gè)強(qiáng)連通分量,而且它的根是當(dāng)前頂點(diǎn)的祖
宗,那么存在包含當(dāng)前頂點(diǎn)的到其祖宗的回路,可知mlik[i]一定被更改為一個(gè)比indx[i]更小的值。
????? 至于如何拿出強(qiáng)連通分量,這個(gè)其實(shí)很簡單,如果當(dāng)前節(jié)點(diǎn)為一個(gè)強(qiáng)連通分量的根,那么它的強(qiáng)連通分量一定是以該根為根節(jié)點(diǎn)的(剩下節(jié)點(diǎn))子
樹。在深度優(yōu)先遍歷的時(shí)候維護(hù)一個(gè)堆棧,每次訪問一個(gè)新節(jié)點(diǎn),就壓入堆?!,F(xiàn)在知道如何拿出了強(qiáng)連通分量了吧?是的,因?yàn)檫@個(gè)強(qiáng)連通分量時(shí)最
先被壓人堆棧的,那么當(dāng)前節(jié)點(diǎn)以后壓入堆棧的并且仍在堆棧中的節(jié)點(diǎn)都屬于這個(gè)強(qiáng)連通分量。當(dāng)然有人會問真的嗎?假設(shè)在當(dāng)前節(jié)點(diǎn)壓入堆棧以后壓
入并且還存在,同時(shí)它不屬于該強(qiáng)連通分量,那么它一定屬于另一個(gè)強(qiáng)連通分量,但當(dāng)前節(jié)點(diǎn)是它的根的祖宗,那么這個(gè)強(qiáng)連通分量應(yīng)該在此之前已經(jīng)
被拿出?,F(xiàn)在沒有疑問了吧,那么算法介紹就完了。
?
題目:Triangle LOVE
?
題意:給定一個(gè)有向圖并規(guī)定:每兩個(gè)點(diǎn)之間一定有邊,同時(shí)A指向B則B定不能指向A,反之亦然。 詢問是否存在僅有三個(gè)點(diǎn)構(gòu)成的環(huán)。
?
思路:
首先判斷有向圖中是否存在環(huán)馬上有tarjan能夠很好的解決。并且如果存在大于三個(gè)點(diǎn)以上的環(huán)的話肯定存在僅有三個(gè)點(diǎn)構(gòu)成的環(huán)。 因?yàn)槊績?/strong>
個(gè)點(diǎn)之間都有邊,并且只有一個(gè)給定的指向,畫幾個(gè)圖便可以推導(dǎo)出這樣的結(jié)論。
證明:?假設(shè)存在一個(gè)n元環(huán),因?yàn)閍->b有邊,b->a必定沒邊,反之也成立 所以假設(shè)有環(huán)上三個(gè)相鄰的點(diǎn)a-> b-> c,那么如果c->a間有邊,就已經(jīng)形
成了一個(gè)三元環(huán),如果c->a沒邊,那么a->c肯定有邊,這樣就形成了一個(gè)n-1元環(huán)。。。。 所以只需證明n為4時(shí)一定有三元環(huán)即可,顯然成立。 所
以知道在tarjan后或中判斷是否存在大于等于三個(gè)點(diǎn)的強(qiáng)連通圖。復(fù)雜度為邊數(shù)即O(n*n)。
?
#include <iostream> #include <string.h> #include <stdio.h>using namespace std;const int N=2005;int head[N],low[N]; int dfn[N],stack[N]; int ans[N]; bool temp[N]; char str[N][N]; int index,m,flag;typedef struct {int to;int next; }Node;Node map[N*N];void add(int u,int v) {map[index].to=v;map[index].next=head[u];head[u]=index++; }void Tarbfs(int k,int lay,int &scc_num) {int t;temp[k]=1;low[k]=lay;dfn[k]=lay;stack[m++]=k;for(int i=head[k];i!=-1;i=map[i].next){t=map[i].to;if(!dfn[t]){Tarbfs(t,++lay,scc_num);if(flag) return;low[k]=min(low[k],low[t]);}if(temp[t]){low[k]=min(low[k],dfn[t]);}}if(dfn[k]==low[k]){++scc_num;while(1){t=stack[--m];temp[t]=0;ans[scc_num]++;if(ans[scc_num]>=3){flag=1;return;}if(t==k) break;}}if(flag) return; }int Tarjan(int n) {int scc_num=0,lay=1;m=0;memset(temp,0,sizeof(temp));memset(low,0,sizeof(low));for(int i=1;i<=n;i++){if(!dfn[i])Tarbfs(i,lay,scc_num);if(flag) break;}return scc_num; }int main() {int i,j,n,t=1,T;scanf("%d",&T);while(T--){scanf("%d",&n);memset(dfn,0,sizeof(dfn));memset(ans,0,sizeof(ans));memset(head,-1,sizeof(head));memset(stack,0,sizeof(stack));index=flag=0;for(i=1;i<=n;i++)scanf("%s",str[i]+1);for(i=1;i<=n;i++){for(j=1;j<=n;j++){if(str[i][j]=='1'){add(i,j);}}}printf("Case #%d: ",t++);Tarjan(n);if(flag) puts("Yes");else puts("No");}return 0; }總結(jié)
以上是生活随笔為你收集整理的HDU4324(强连通的Tarjan算法)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: POJ1734(floyd求最小环的路径
- 下一篇: HDU4389(数位DP)