• 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
    ");
    83         else printf("No
    ");
    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)
    }
  • 相关阅读:
    [原创] 如何在ietester下使用firebug
    Undeclared identifier: 'XXXX'
    图解SQL多表关联查询
    如何去掉Delphi自动生成的~.pas等临时文件
    DataSetProvider的Option属性
    DELPHI DATASNAP 2010 入门操作(2)不写一行代码,绿色三层我也行
    Windows下搭建Android开发环境
    Delphi快捷键大全
    DevExpress的TcxDBLookupComboBox使用方法及问题
    SQL的重复记录处理大全
  • 原文地址:https://www.cnblogs.com/LK1994/p/3330758.html
Copyright © 2020-2023  润新知