Tarjan各大算法汇总

Posted sun123zxy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tarjan各大算法汇总相关的知识,希望对你有一定的参考价值。

补丁V2.3 增加了割边,割点(前向星)代码

补丁V2.0 计划内容增大,增加了割点(邻接矩阵)代码

补丁V1.1 简化了Tarjan(邻接矩阵)代码

备忘:简化强联通分量(前向星)代码,割边需处理重边,增加其他tarjan算法


强联通分量

邻接矩阵
//邻接矩阵 by sun123zxy 
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<queue>
//#include<windows.h>
using namespace std;

int n,m;
int map[1005][1005];
int book[1005];
int instack[1005];
int stack[1005];
int top=0;
int low[1005];
int dfn[1005];
int dfnn=1;

void tarjan(int note) {
    instack[note]=1;
    book[note]=1;
    dfn[note]=dfnn;
    dfnn++;

    stack[top]=note;
    top++;

    low[note]=dfn[note];
    for(int i=1; i<=n; i++) {
        if(map[note][i]==1) {
            if(instack[i]==1) {
                if(low[note]>dfn[i]) {
                    low[note]=dfn[i];
                }
            } else if(book[i]==1) {

            } else {
                tarjan(i);
                if(low[note]>low[i]) {
                    low[note]=low[i];
                }
            }
        }
    }

    if(dfn[note]==low[note]) {
        for(;;) {
            
            printf("%d",stack[top-1]);//输出分量 
            
            instack[stack[top-1]]=0;
            top--;
            if(stack[top]==note) {
                break;
            }
        }
    }
}

int main() {
    cin>>n>>m;
    for(int i=1;i<=m; i++) {
        int t1,t2;
        scanf("%d%d",&t1,&t2);
        map[t1][t2]=1;
    }
    
    for(int i=1;i<=n;i++){ 
        if(book[i]==0){
            tarjan(i);
        }
    }
    return 0;
}
前向星
#include<iostream>  
#include<iomanip>  
#include<cstring>  
#include<cmath>  
#include<cstdio>  
#include<algorithm>  
using namespace std;  
  
int n,m;  
  
struct uct1 {  
    int from,to;  
} edge[50005];  
int first[50005];  
int len[50005];  
  
int dfn[50005];  
int low[50005];  
int stack[50005];  
int top=0;  
int instack[50005]= {0};  
int book[50005]= {0};  
int dfnn=0;  
  
int cmp(uct1 a,uct1 b) {  
    return a.from<b.from;  
}  
  
void tarjan(int now) {  
    if(first[now]==0){  
        return;  
    }  
    for(int i=first[now];i<first[now]+len[now] ; i++) {  
        int ito=edge[i].to;  
        if(instack[ito]==1) {  
            if(low[now]>dfn[ito]) {  
                low[now]=dfn[ito];  
            }  
            continue;  
        } else if(book[ito]==1) {  
            continue;  
        } else {  
            book[ito]=1;  
            instack[ito]=1;  
            stack[top]=ito;  
            top++;  
            dfnn++;  
            dfn[ito]=dfnn;  
            low[ito]=dfn[ito];  
            tarjan(ito);  
  
            if(low[now]>low[ito]) {  
                low[now]=low[ito];  
            }  
  
            if(low[ito]==dfn[ito]) {  
                for(;;) {  
                    printf("%d ",stack[top-1]);  
                    instack[stack[top-1]]=0;  
                    top--;  
                    if(stack[top]==ito) {  
                        break;  
                    }  
                }  
                cout<<endl;  
            }  
        }  
  
    }  
}  
  
int main() {  
    cin>>n>>m;  
  
    for(int i=1; i<=m; i++) {  
        int t1,t2;  
        scanf("%d%d",&t1,&t2);  
        edge[i].from=t1;  
        edge[i].to=t2;  
    }  
    sort(edge+1,edge+m+1,cmp);  
      
    first[edge[1].from]=1;  
    len[edge[1].from]=1;  
    for(int i=2; i<=m; i++) {  
        if(edge[i].from!=edge[i-1].from) {  
            first[edge[i].from]=i;  
        }  
        len[edge[i].from]++;  
    }  
    for(int i=1; i<=n; i++) {  
        if(book[i]==0) {  
            book[i]=1;  
            instack[i]=1;  
            stack[top]=i;  
            top++;  
            dfnn++;  
            dfn[i]=dfnn;  
            low[i]=dfn[i];  
            tarjan(i);  
            if(low[i]==dfn[i]) {  
                for(;;) {  
                    if(top==0) {  
                        break;  
                    }  
                    printf("%d ",stack[top-1]);  
                    instack[stack[top-1]]=0;  
                    top--;  
                }  
                cout<<endl;  
            }  
            for(int i=0; i<2005; i++) {  
                instack[i]=0;  
            }  
            dfnn=0;  
        }  
    }  
    return 0;  
}  

割点

邻接矩阵
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<queue>
//#include<windows.h>
using namespace std;

int n,m;
int map[105][105];
int book[105];
int instack[105];
int stack[105];
int top=0;
int low[105];
int dfn[105];
int dfnn=1;
int ans[105];
int ansn=0;

void tarjan(int note,int fa) {
    int chin=0;//记录该点孩子个数,判定根节点是否为割点时用
    instack[note]=1;
    book[note]=1;
    dfn[note]=dfnn;
    dfnn++;

    stack[top]=note;
    top++;

    low[note]=dfn[note];
    for(int i=1; i<=n; i++) {
        if(map[note][i]==1&&i!=fa) {
            chin++;
            if(instack[i]==1) {
                if(low[note]>dfn[i]) {
                    low[note]=dfn[i];
                }
            } else if(book[i]==1) {

            } else {
                tarjan(i,note);
                if(low[note]>low[i]) {
                    low[note]=low[i];
                }
                if(fa==-1) {//若为根节点
                    if(chin>=2){//若孩子数大于等于2,是割点
                        ans[ansn]=note;
                        ansn++;
                    }
                } else {
                    if(dfn[note]<=low[i]) {
                        ans[ansn]=note;
                        ansn++;
                    }
                }
            }
        }
    }

    if(dfn[note]==low[note]) {
        for(;;) {
            instack[stack[top-1]]=0;
            top--;
            if(stack[top]==note) {
                break;
            }
        }
    }
}

int main() {
    cin>>n>>m;

    for(int i=1; i<=m; i++) {
        int t1,t2;
        scanf("%d%d",&t1,&t2);
        map[t1][t2]=1;
        map[t2][t1]=1;
    }

    tarjan(1,-1);
    
    cout<<ansn<<endl;
    for(int i=0; i<ansn; i++) {//需进一步去重,因为如有一点可能成为多个割点。e.g:1-2,2-3,2-4
        cout<<ans[i]<<‘ ‘;
    }

    return 0;
}
前向星
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<queue>
using namespace std;

struct uct1 {
    int from,to;
} edge[100005];
int first[100005];
int size[100005];

int n,m;
int book[100005];
int instack[100005];
int stack[100005];
int top=0;
int low[100005];
int dfn[100005];
int dfnn=1;
int ans[100005];
int ansn=0;

void tarjan(int note,int fa) {
    int chin=0;//记录该点孩子个数,判定根节点是否为割点时用
    instack[note]=1;
    book[note]=1;
    dfn[note]=dfnn;
    dfnn++;

    stack[top]=note;
    top++;

    low[note]=dfn[note];

    for(int ti=first[note]; ti<=first[note]+size[note]-1; ti++) {
        int i=edge[ti].to;
        if(i!=fa) {
            chin++;
            if(instack[i]==1) {
                if(low[note]>dfn[i]) {
                    low[note]=dfn[i];
                }
            } else if(book[i]==1) {

            } else {
                tarjan(i,note);
                if(low[note]>low[i]) {
                    low[note]=low[i];
                }
                if(fa==-1) {//若为根节点
                    if(chin>=2) { //若孩子数大于等于2,是割点
                        ans[ansn]=note;
                        ansn++;
                    }
                } else {
                    if(dfn[note]<=low[i]) {
                        ans[ansn]=note;
                        ansn++;
                    }
                }
            }
        }
    }

    if(dfn[note]==low[note]) {
        for(;;) {
            instack[stack[top-1]]=0;
            top--;
            if(stack[top]==note) {
                break;
            }
        }
    }
}

bool cmp(uct1 x,uct1 y) {
    if(x.from<y.from) {
        return 1;
    } else if(x.from>y.from) {
        return 0;
    } else {
        return x.to<y.to;
    }
}

int main() {
    cin>>n>>m;
    m=m*2;
    for(int i=1; i<=m; i+=2) {
        int t1,t2;
        scanf("%d%d",&t1,&t2);
        edge[i].from=t1;
        edge[i].to=t2;
        edge[i+1].from=t2;
        edge[i+1].to=t1;
    }
    sort(edge+1,edge+1+m,cmp);

    for(int i=1; i<=m; i++) {
        if(edge[i].from!=edge[i-1].from) {
            first[edge[i].from]=i;
        }
        size[edge[i].from]++;
    }

    tarjan(1,-1);

    cout<<ansn<<endl;
    for(int i=0; i<ansn; i++) {//需进一步去重,因为有点可能多次被判定为割点。e.g:1-2,2-3,2-4
        cout<<ans[i]<<‘ ‘;
    }
    return 0;
}

割边

邻接矩阵(未处理重边)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<queue>
//#include<windows.h>
using namespace std;

int n,m;
int map[5005][5005];
int book[5005];
int instack[5005];
int stack[5005];
int top=0;
int low[5005];
int dfn[5005];
int dfnn=1;
int ans=0;

void tarjan(int note,int fa) {
    instack[note]=1;
    book[note]=1;
    dfn[note]=dfnn;
    dfnn++;

    stack[top]=note;
    top++;

    low[note]=dfn[note];
    for(int i=1; i<=n; i++) {
        if(map[note][i]==1&&i!=fa) {
            if(instack[i]==1) {
                if(low[note]>dfn[i]) {
                    low[note]=dfn[i];
                }
            } else if(book[i]==1) {

            } else {
                tarjan(i,note);
                if(low[note]>low[i]) {
                    low[note]=low[i];
                }
                if(dfn[note]<low[i]) {
                    ans++;
                }
            }
        }
    }

    if(dfn[note]==low[note]) {
        for(;;) {
            instack[stack[top-1]]=0;
            top--;
            if(stack[top]==note) {
                break;
            }
        }
    }
}

int main() {
    cin>>n>>m;
    for(int i=1; i<=m; i++) {
        int t1,t2;
        scanf("%d%d",&t1,&t2);
        map[t1][t2]=1;
        map[t2][t1]=1;
    }

    tarjan(1,-1);
    cout<<ans<<endl;

    return 0;
}
前向星(未处理重边)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<queue>
using namespace std;

struct uct1{
    int from,to;
}edge[100005];
int first[100005];
int size[100005];

int n,m;
int book[100005];
int instack[100005];
int stack[100005];
int top=0;
int low[100005];
int dfn[100005];
int dfnn=1;
int ans=0;

void tarjan(int note,int fa) {
    instack[note]=1;
    book[note]=1;
    dfn[note]=dfnn;
    dfnn++;

    stack[top]=note;
    top++;

    low[note]=dfn[note];
    
    for(int ti=first[note]; ti<=first[note]+size[note]-1; ti++) {
        int i=edge[ti].to;
        if(i!=fa) {
            if(instack[i]==1) {
                if(low[note]>dfn[i]) {
                    low[note]=dfn[i];
                }
            } else if(book[i]==1) {

            } else {
                tarjan(i,note);
                if(low[note]>low[i]) {
                    low[note]=low[i];
                }
                if(dfn[note]<low[i]) {
                    ans++;
                }
            }
        }
    }

    if(dfn[note]==low[note]) {
        for(;;) {
            instack[stack[top-1]]=0;
            top--;
            if(stack[top]==note) {
                break;
            }
        }
    }
}

bool cmp(uct1 x,uct1 y){
    if(x.from<y.from){
        return 1;
    }else if(x.from>y.from){
        return 0;
    }else{
        return x.to<y.to;
    }
}

int main() {
        cin>>n>>m;
        m=m*2;
        for(int i=1; i<=m; i+=2) {
            int t1,t2;
            scanf("%d%d",&t1,&t2);
            edge[i].from=t1;
            edge[i].to=t2;
            edge[i+1].from=t2;
            edge[i+1].to=t1;
        }
        sort(edge+1,edge+1+m,cmp);
        
        for(int i=1;i<=m;i++){
            if(edge[i].from!=edge[i-1].from){
                first[edge[i].from]=i;
            }
            size[edge[i].from]++;
        }
        
        tarjan(1,-1);
        cout<<ans<<endl;
    
    return 0;
}

以上是关于Tarjan各大算法汇总的主要内容,如果未能解决你的问题,请参考以下文章

排序算法大汇总

排序算法大汇总

tarjan割点算法代码实现

各大互联网Java面试题汇总,最后我成功拿到百度的offer

各大互联网企业Java面试题汇总,看我如何成功拿到百度的offer

HDU 1269 迷宫城堡 tarjan算法求强连通分量