tarjan解惑

· · 个人记录

如果你感觉tarjan算法很玄,如果你对其似懂非懂,本篇题解很适合你

小白转 https://zhuanlan.zhihu.com/p/101923309

if (vis[v])  low[x]=min(low[x],low[v]);

而必须写教材上的

if (vis[v])  low[x]=min(low[x],dfn[v]);
if条件判定可以省略,直接写

```c
 low[x]=min(low[x],dfn[v]);

下文中,我将对以上误区作说明

一、震惊!两个tarjan

误区3是对算法的刻板理解,事实上,两个tarjan都是对的,它们的搜索过程、栈处理、dfn处理无任何区别,但low值有微妙差别 (不用担心,如果用dfn[x]==low[x]作出栈判定条件是无影响的)

注意学习中辨别张冠李戴的论述

二、栈的意义

两个tarjan有相同的栈处理,栈是low的前提

预告一下,该栈非常玄学,不一定是链,也不一定包含什么SCC,很像是各个SCC假肢拼凑到一起( 这么血腥的吗

三、low与low'的意义

四、栈判定的必要性

来解答误区4,如果没有vis判定,搜索到顶点x时,会怎么样呢?

五、吐槽一下

似乎tarjan可解释性质并不好,很奇怪为什么不用深度而用dfn和low,求大佬解答。不管怎样,附代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const LL maxLL=1e15;
const LL maxn=2e4;
const LL maxm=2e5;
int n,i,j,L,k,m,x,t,c,y;
int a[maxn],v[maxn],f[maxn];
int hea[maxn],poi[maxm],nex[maxm];
int HEA[maxn],POI[maxm],NEX[maxm];
int low[maxn],dfn[maxn],col[maxn];
int sta[maxn];
deque<int> q;

void PW(int i,int j)
{
    if(i==j) return;
    x++; poi[x]=j; nex[x]=hea[i];hea[i]=x;
}

int top(){return sta[sta[0]];}
void push(int x){sta[++sta[0]]=x;f[x]=1;}
void pop(){f[top()]=0;sta[0]--;}

void tj(int c,int from)
{
    //printf("tj %d %d\n",c,f[7]);
    k++; dfn[c]=low[c]=k;
    push(c);
    int i,y;
    for(i=hea[c];i;i=nex[i])
    {
        y=poi[i];
        if(dfn[y])
        {
            if(f[y]) 
                low[c]=min(low[c],dfn[y]);
        }else
        {
            tj(y,c);
            low[c]=min(low[c],low[y]);
        }
    }
    if(low[c]==dfn[c])
    {
        //printf("%d\n",c);
        col[0]++;
        while(top()!=c) col[top()]=col[0], pop();
        col[top()]=col[0],pop();
    }
}
void SD()
{
    k=0;
    for(i=1;i<=n;i++)
        if(dfn[i]==0)
            tj(i,0);/*
    for(i=1;i<=n;i++)
        printf("%d dfn=%d col=%d low=%d\n",
        i,dfn[i],col[i],low[i]);*/
    x=0;
    for(i=1;i<=n;i++)
        v[col[i]]+=a[i];
    for(i=1;i<=n;i++)
    {
        for(j=hea[i];j;j=nex[j])
            POI[j]=poi[j],
            NEX[j]=nex[j];
        HEA[i]=hea[i],hea[i]=0;
    }
    x=0;
    for(i=1;i<=n;i++)
        for(j=HEA[i];j;j=NEX[j])
            PW(col[i],col[POI[j]]);
    n=col[0];

}
int main()
{
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++) scanf("%d",&a[i]);
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&j,&t);
        PW(j,t);
    }
    SD();/*
    for(i=1;i<=n;i++)
    {
        printf("%d v=%d:\n",i,v[i]);
        for(j=hea[i];j;j=nex[j]) printf("%d ",poi[j]);
        printf("\n");
    }*/
    memset(a,0,sizeof(a));
    memset(f,0,sizeof(f));
    for(i=1;i<=n;i++)
        for(j=hea[i];j;j=nex[j])
        {
            a[poi[j]]++;

        }
    for(i=1;i<=n;i++) if(a[i]==0) q.push_back(i),f[i]=v[i];
    while(!q.empty())
    {
        c=q.front(); q.pop_front();
        //printf(":%d\n",c);
        for(i=hea[c];i;i=nex[i])
        {
            y=poi[i];
            f[y]=max(f[y],f[c]+v[y]);
            a[y]--;
            if(a[y]==0)
                q.push_back(y);
        }
    }
    for(i=1;i<=n;i++) f[0]=max(f[0],f[i]);
    printf("%d",f[0]);

}