HDOJ迷宫城堡(判断强连通 tarjan算法)

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5400    Accepted Submission(s): 2411


Problem Description
为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明可以通过这个通道由A房间到达B房间,但并不说明通过它可以由B房间到达A房间。Gardon需要请你写个程序确认一下是否任意两个房间都是相互连通的,即:对于任意的i和j,至少存在一条路径可以从房间i到房间j,也存在一条路径可以从房间j到房间i。
 

 

Input
输入包含多组数据,输入的第一行有两个数:N和M,接下来的M行每行有两个数a和b,表示了一条通道可以从A房间来到B房间。文件最后以两个0结束。
 

 

Output
对于输入的每组数据,如果任意两个房间都是相互连接的,输出"Yes",否则输出"No"。
 

 

Sample Input
3 3
1 2
2 3
3 1
3 3
1 2
2 3
3 2
0 0
 

 

Sample Output
Yes
No
 
题意很清楚,就是判断有向图是否是强连通图,即图中任意两点是不是可以相互可达;
新学的tarjan算法,理解的还不是很透彻,参考着伪代码和大神的代码敲得;
 1 #include<stdio.h>

 2 #include<string.h>

 3 #include<vector>

 4 #include<algorithm>

 5 using namespace std;

 6 

 7 vector<int>edge[10010];//用邻接表存图;

 8 int n,m;

 9 int dfn[10010];//深度优先搜索访问次序,记录u第一次被访问的步数;

10 int low[10010];//能追溯到的最早的次序;

11 int st[10010];//tarjan中的栈;

12 int din; //索引号;

13 int num; //强连通分量个数;

14 int top; //栈中元素个数;

15 int in[10010];//是否在栈中;

16 

17 void tarjan(int u)

18 {

19     int i,j;

20     int v;

21     dfn[u] = low[u] = ++din;//为节点u设定访问序号;

22     in[u] = 1;

23     st[++top] = u;//压入栈中

24     for(i = 0; i < edge[u].size(); i++)//遍历与u相连的节点

25     {

26         v = edge[u][i];

27         if(!dfn[v])//如果节点v未被访问过

28         {

29             tarjan(v);//继续向下访问

30             low[u] = min(low[u],low[v]);

31         }

32         else if(in[v])//如果节点v已被访问过,并且已在栈中

33         {

34             low[u] = min(low[u],dfn[v]);

35         }

36     }

37 

38     if(dfn[u] == low[u])//如果节点u是强连通分量的根

39     {

40         num++;//连通分量数加1;

41         do

42         {

43             j = st[top--];

44             in[j] = 0;

45         }

46         while(j != u);//将该强连通分量中的节点退栈,

47     }

48 

49 }

50 void init()

51 {

52     int i;

53     memset(dfn,0,sizeof(dfn));

54     top = 0;

55     num = 0;

56     din = 0;

57     for(i = 1; i <= n; i++)

58     {

59         if(!dfn[i])

60         {

61             tarjan(i);

62         }

63     }

64 

65 }

66 int main()

67 {

68     int u,v;

69     while(~scanf("%d %d",&n,&m))

70     {

71         if(n == 0 && m == 0)

72             break;

73         for(int i = 0; i <= n; i++)

74             edge[i].clear();

75         while(m--)

76         {

77             scanf("%d %d",&u,&v);

78             edge[u].push_back(v);

79         }

80         init();

81         if(num == 1)

82             printf("Yes\n");

83         else printf("No\n");

84     }

85     return 0;

86 }
View Code

 

 

实例代码

?

tarjan(u)

{
DFN[u]=Low[u]=++Index //为节点u设定次序编号和Low初值
Stack.push(u) // 将节点u压入栈中
foreach (u, v)in E // 枚举每一条边
if(v is not visted) // 如果节点v未被访问过
tarjan(v) //继续向下找
Low[u]= min(Low[u], Low[v])
elseif(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)
}

你可能感兴趣的:(tar)