Tarjan 算法模板+几个好的博客地址

之前只会kosaraju算法(因为这个好懂= _ =),后来做到一些强连通性的题目时,因为这个时间复杂度太高了,所以做不出来,知道另外一个求图的强连通性的算法——Tarjan算法,就是网上找那些大佬的对Tarjan算法 的理解,也是花了一天多的时间才看懂这个算法。

这里给上三个比较好懂的博客地址:

浅析强连通分量(Tarjan和kosaraju)

全网最!详!细!tarjan算法讲解

tarjan求强连通分量+缩点+割点/割桥(点双/边双)以及一些证明

强推最后一个!!!!



Tarjan模板

#include<cstdio>
#include<stack>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=110000;
int n,m,idx=0,k=1,Bcnt=0;
int head[N];
int ins[N];
int dfn[N]//dfn[ ],表示这个点在dfs时是第几个被搜到的。
int low[N];//low[ ],表示这个点以及其子孙节点连的所有点中dfn最小的值   
int Belong[N];//点属于哪个强连通分量
stack <int> s;
struct edge
{
    int v,next;
}e[N*2];

void adde(int u,int v)//建边
{
     e[k].v=v;
     e[k].next=head[u];
     head[u]=k++;
}
void readdata()//读边
{
     int a,b;
     memset(head,-1,sizeof(head));
     scanf("%d%d",&n,&m);
     for(int i=1;i<=m;i++)
     {
         scanf("%d%d",&a,&b);
         adde(a,b);
     }
}
void tarjan(int u)
{
     int v;
     dfn[u]=low[u]=++idx;//每次dfs,u的次序号增加1
     s.push(u);//将u入栈
     ins[u]=1;//标记u在栈内
     for(int i=head[u];i!=-1;i=e[i].next)//访问从u出发的边
     {
         v=e[i].v;
         if(!dfn[v])//如果v没被处理过
         {
             tarjan(v);//dfs(v)
             low[u]=min(low[u],low[v]);//u点能到达的最小次序号是它自己能到达点的最小次序号和连接点v能到达点的最小次序号中较小的
         }
         else if(ins[v])low[u]=min(low[u],dfn[v]);//如果v在栈内,u点能到达的最小次序号是它自己能到达点的最小次序号和v的次序号中较小的
     }
     if(dfn[u]==low[u])                           //if(dfn[u]==low[u])//边搜边输出
     {                                            //{
         Bcnt++;                                  //  do
         do                                       //  {
         {                                        //    printf("%d ",s.top());
             v=s.top();                           //    s.pop();
             s.pop();                             //    ins[v]=0;
             ins[v]=0;                            //  }while(u!=v);
             Belong[v]=Bcnt;                      //  printf("\n");
         }while(u != v);                          //}
     }
}
void work()
{
     for(int i=1;i<=n;i++)
     {
      	if(!dfn[i]) tarjan(i);
     }
     //printf("\n");
     //for(int i = 1;i <= 6;i++)printf("%d %d\n",dfn[i],low[i]);
     //printf("%d\n",Bcnt);
     for(int i=1;i<=Bcnt;i++)
     {
        //printf("No.%d:",i);
        for(int j=1;j<=n;j++)
        {
           if(Belong[j]==i)printf("%d ",j);
        }
        printf("\n");
     }
}
int main()
{
  readdata();
  work();
  return 0;
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值