• 图论算法》关于tarjan算法两三事


      关于tarjan,在下觉得这个算法从本质上是一种暴力求强连通分量的方法,但事实上这也是最有效的求强连通分量的方法之一,它对于处理各种强连通分量中奇怪问题,都可以直接转化,所以比较通用和常见。

      什么是tarjan

      粗略的描述一下(详细描述在百度里很详细)

      首先每个点都有时间戳和最小子树戳。

      时间戳的定义是这个点进行递归的时间,每新递归一次就增加,所以每个点的时间戳都不一样,最小子树戳的定义是当前点的子树上节点中(包括它自己)时间戳的最小值。

      它的基本方法是先把任意一个没有tarjan过的点加入栈,然后把新加入的点当做一棵树的根做处理,先把自己的时间戳和最小子树戳设为自己,然后每次去找根的所链的每条边,如果当前边所接的目标节点没有进行过tarjan,那就再tarjan递归处理,处理后,对比当前点最小子树戳和所搜目标节点的最小子树戳,取最小值;如果已经进行过tarjan,但是当前所搜到的目标节点不在栈里(也就是非当前点的来源节点),那么就什么也不做(因为只要这点进过tarjan就说明一定已经把它所处的强连通分量找过,并且找全,但你当前所处理的点是没进过tarjan的,所以一定不和这种进过栈但当前不在栈的点属于一个强连通分量);最后一种情况进行过tarjan并且当前点再栈里,那么我们只需要对比当前点的最小子树戳和目标节点的时间戳,取最小值。

      如果搜索子树的工作结束了,那么要判断是否当前递归节点的时间戳和最小子树戳相同:如果相同,那么从这个节点一直到栈顶都属于同一个强连通分量,全部弹出;如果不同,结束当前递归。

    先贴出tarjan的模板

     1 void tarjan(int sb)
     2 {
     3     low[sb]=time[sb]=++T;
     4     f[sb]=true;
     5     stack[++ass]=sb;
     6     for(int k=head[sb];k!=0;k=e[k].next)
     7     {
     8         if(!time[e[k].aim])
     9         {
    10             tarjan(e[k].aim);
    11             low[sb]=min(low[sb],low[e[k].aim]);
    12         }
    13         else if(f[e[k].aim])low[sb]=min(low[sb],time[e[k].aim]);
    14     }
    15     if(time[sb]==low[sb])
    16     {
    17         f[sb]=false;
    18         while(stack[ass]!=sb)
    19             f[stack[ass--]]=false;
    20         ass--;
    21     }
    22 }

    在此提供一道tarjan裸

      codevs1332

      在幻想乡,上白泽慧音是以知识渊博闻名的老师。春雪异变导致人间之里的很多道路都被大雪堵塞,使有的学生不能顺利地到达慧音所在的村庄。因此慧音决定换一个能够聚集最多人数的村庄作为新的教学地点。人间之里由N个村庄(编号为1..N)和M条道路组成,道路分为两种一种为单向通行的,一种为双向通行的,分别用1和2来标记。如果存在由村庄A到达村庄B的通路,那么我们认为可以从村庄A到达村庄B,记为(A,B)。当(A,B)和(B,A)同时满足时,我们认为A,B是绝对连通的,记为<A,B>。绝对连通区域是指一个村庄的集合,在这个集合中任意两个村庄X,Y都满足<X,Y>。现在你的任务是,找出最大的绝对连通区域,并将这个绝对连通区域的村庄按编号依次输出。若存在两个最大的,输出字典序最小的,比如当存在1,3,4和2,5,6这两个最大连通区域时,输出的是1,3,4。

    输入描述 Input Description

    第1行:两个正整数N,M

    第2..M+1行:每行三个正整数a,b,t, t = 1表示存在从村庄a到b的单向道路,t = 2表示村庄a,b之间存在双向通行的道路。保证每条道路只出现一次。

    输出描述 Output Description

    第1行: 1个整数,表示最大的绝对连通区域包含的村庄个数。

    第2行:若干个整数,依次输出最大的绝对连通区域所包含的村庄编号。

    下面贴出手写代码

     1 #include<cstdio>
     2 struct shit{
     3     int aim;
     4     int next;
     5     bool use;
     6 }e[50100];
     7 int max(int x,int y)
     8 {
     9     return x>y?x:y;
    10 }
    11 int min(int x,int y)
    12 {
    13     return x<y?x:y;
    14 }
    15 int point,head[5100],n,m,ass,cnt,stack[51000],low[51000],time[51000],ans[51000],a,b,num,T,cl2[51000],cl[10];
    16 bool f[51000];
    17 void fuck(int x,int y)
    18 {
    19     e[++point].aim=y;
    20     e[point].next=head[x];
    21     head[x]=point;
    22 }
    23 void tarjan(int sb)
    24 {
    25     int x=ass;
    26     stack[++ass]=sb;
    27     f[sb]=true;
    28     low[sb]=time[sb]=++T;
    29     for(int k=head[sb];k!=0;k=e[k].next)
    30     {
    31         int c=e[k].aim;
    32         if(!time[c])
    33         {
    34             tarjan(c);
    35             low[sb]=min(low[sb],low[c]);
    36         }
    37         else if(f[c])low[sb]=min(low[sb],time[c]);
    38     }
    39     if(low[sb]==time[sb])
    40     {
    41         cnt++;
    42         if(ass-x>=cl[0])
    43         {
    44             cl[0]=ass-x;
    45             cl[1]=cnt;
    46         }
    47         for(int i=1;i<=ass-x;i++)
    48         {
    49             cl2[stack[x+i]]=cnt;
    50                 f[stack[x+i]]=false;
    51         }
    52         ass=x;
    53     }
    54     return;
    55 }
    56 int main()
    57 {
    58     scanf("%d%d",&n,&m);
    59     for(int i=1;i<=m;i++)
    60     {
    61         scanf("%d%d%d",&a,&b,&num);
    62         if(num-1)fuck(b,a);
    63          fuck(a,b);
    64     }
    65     for(int i=1;i<=n;i++)
    66         if(!time[i])tarjan(i);
    67     printf("%d
    ",cl[0]);
    68     point=0;
    69     for(int i=1;i<=n;i++)
    70     {
    71         if(cl2[i]==cl[1])ans[++point]=i;
    72     }
    73     for(int i=1;i<=cl[0];i++)
    74     {
    75         printf("%d ",ans[i]);
    76     }
    77     return 0;
    78 }
    View Code

     

  • 相关阅读:
    Phpstorm+Xdebug配置
    ThinkPHP5.0---URL访问
    Thinkphp5创建控制器
    ThinkPHP5.0的安装
    网页动态背景——随鼠标变换的动态线条
    git SSH
    [go] 循环与函数
    svg make a face
    Hello Vizhub
    Beetlsql自定义生成entity,mapper,md代码
  • 原文地址:https://www.cnblogs.com/PencilWang/p/5868023.html
Copyright © 2020-2023  润新知