HDU OJ 1269 迷宮城堡【有向圖強連通分量的Tarjan算法 入門】

原題連接:http://acm.hdu.edu.cn/showproblem.php?pid=1269

題意:~~~~~;

思路:就是判斷圖是否是 強連通圖;

有向圖強連通分量的Tarjan算法:

[有向圖強連通分量]

在有向圖G中,如果兩個頂點間至少存在一條路徑,稱兩個頂點強連通(strongly connected)。如果有向圖G的每兩個頂點都強連通,稱G是一個強連通圖。非強連通圖有向圖的極大強連通子圖,稱爲強連通分量(strongly connected components)。

下圖中,子圖{1,2,3,4}爲一個強連通分量,因爲頂點1,2,3,4兩兩可達。{5},{6}也分別是兩個強連通分量。

wps_clip_image-24103

 

大體來說有3中算法Kosaraju,Trajan,Gabow這三種!後續文章中將相繼介紹,首先介紹Tarjan算法

 

[Tarjan算法]

Tarjan算法是基於對圖深度優先搜索的算法,每個強連通分量爲搜索樹中的一棵子樹。搜索時,把當前搜索樹中未處理的節點加入一個堆棧,回溯時可以判斷棧頂到棧中的節點是否爲一個強連通分量。

 

定義DFN(u)爲節點u搜索的次序編號(時間戳),Low(u)爲u或u的子樹能夠追溯到的最早的棧中節點的次序號。

 

算法僞代碼如下

tarjan(u) 
{

    DFN[u]=Low[u]=++Index     // 爲節點u設定次序編號和Low初值

    Stack.push(u)                     // 將節點u壓入棧中

    for each (u, v) in E               // 枚舉每一條邊

          if (v is not visted)          // 如果節點v未被訪問過

                  tarjan(v)              // 繼續向下找

                  Low[u] = min(Low[u], Low[v])

            else if (v in S)            // 如果節點v還在棧內

            Low[u] = min(Low[u], DFN[v])

    if (DFN[u] == Low[u])        // 如果節點u是強連通分量的根

       repeat

           v = S.pop                  // 將v退棧,爲該強連通分量中一個頂點

           print v

      until (u== v)

}

 

接下來是對算法流程的演示。

從節點1開始DFS,把遍歷到的節點加入棧中。搜索到節點u=6時,DFN[6]=LOW[6],找到了一個強連通分量。退棧到u=v爲止,{6}爲一個強連通分量。

wps_clip_image-16442

返回節點5,發現DFN[5]=LOW[5],退棧後{5}爲一個強連通分量。

wps_clip_image-24939

返回節點3,繼續搜索到節點4,把4加入堆棧。發現節點4向節點1有後向邊,節點1還在棧中,所以LOW[4]=1。節點6已經出棧,(4,6)是橫叉邊,返回3,(3,4)爲樹枝邊,所以LOW[3]=LOW[4]=1。

wps_clip_image-17734

繼續回到節點1,最後訪問節點2。訪問邊(2,4),4還在棧中,所以LOW[2]=DFN[4]=5。返回1後,發現DFN[1]=LOW[1],把棧中節點全部取出,組成一個連通分量{1,3,4,2}。

wps_clip_image-10846

至此,算法結束。經過該算法,求出了圖中全部的三個強連通分量{1,3,4,2},{5},{6}。

可以發現,運行Tarjan算法的過程中,每個頂點都被訪問了一次,且只進出了一次堆棧,每條邊也只被訪問了一次,所以該算法的時間複雜度爲O(N+M)。

AC 代碼:

#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
const int Max=11000;
#define min(a,b) a>b?b:a
int n,m,top,index;
int instack[Max],stack[Max],loop[Max];
int DFN[Max],LOW[Max],ans;
vector<int> V[Max];
void init()
{
	top=ans=0;
	index=1;
	int i;
	for(i=0;i<Max;i++)
	{
		V[i].clear();
		loop[i]=0;
		instack[i]=0;
	}
}
void tarjan(int u)
{
	int i,j,v;
	LOW[u]=DFN[u]=index++;
	stack[top++]=u;
	loop[u]=1;
	instack[u]=1;
	for(i=0;i<V[u].size();i++)
	{
		v=V[u][i];
		if(loop[v]==0)
		{
			tarjan(v);
			LOW[u]= min(LOW[u],LOW[v]);
		}
	   else if(instack[v])
			LOW[u]= min(LOW[u],DFN[v]);
		
	}
	if(DFN[u]==LOW[u])
	{
		do{
			j=stack[top-1];
			instack[i]=0;
			top--;
		}while(j!=u);
		ans++;
	}
}
int main()
{
	int i,j,x,y;
	while(~scanf("%d%d",&n,&m)&&n+m)
	{
		init();
		for(i=1;i<=m;i++)
		{
			scanf("%d%d",&x,&y);
			V[x].push_back(y);
		}
		for(i=1;i<=n;i++)
			if(loop[i]==0)
		           tarjan(i);
		if(ans==1||n==1)
			printf("Yes\n");
		else
			printf("No\n");
	}
}



發佈了81 篇原創文章 · 獲贊 184 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章