1. 程式人生 > >Tarjan各大算法匯總

Tarjan各大算法匯總

未處理 cstring else break 等於 window str clu 一點

補丁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各大算法匯總