tarjan,割边,桥,割点

这里是tarjan的基础知识,

求割点和割边


 

先来求割边,

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <bits/stdc++.h>
  4 using namespace std;
  5 typedef long long ll;
  6 typedef unsigned long long ull;
  7 
  8 #define ls (t<<1)
  9 #define rs ((t<<1)|1)
 10 #define mid ((l+r)>>1)
 11 
 12 #define mk make_pair
 13 #define pb push_back
 14 #define fi first
 15 #define se second
 16 
 17 #define MAXN 100001
 18 struct edge {
 19     int v,nxt;
 20 } e[MAXN*2];
 21 int head[MAXN];
 22 bool qiao[MAXN*2];
 23 int dfn[MAXN],low[MAXN];
 24 int n,m,cnt,num;
 25 int c[MAXN],dcc;
 26 //c[i]为i节点所在边双联通块编号 
 27 void add(int x,int y) {
 28     e[++cnt].v=y,e[cnt].nxt=head[x],head[x]=cnt;
 29 }
 30 void tarjan(int x,int fa) {
 31     dfn[x]=low[x]=++num;
 32     for (int i=head[x]; i; i=e[i].nxt) {
 33         int y=e[i].v;
 34         if (!dfn[y]) {
 35             tarjan(y,i);
 36             low[x]=min(low[x],low[y]);
 37             if (low[y]>dfn[x]) {
 38                 qiao[i]=qiao[i^1]=1;
 39             }
 40         } else if(i!=(fa^1)) {
 41             low[x]=min(low[x],dfn[y]);
 42         }
 43     }
 44 }
 45 
 46 void dfs(int x) {
 47     c[x]=dcc;
 48     for (int i=head[x];i;i=e[i].nxt) {
 49         int y=e[i].v;
 50         if (c[y]||qiao[i]) continue;
 51         dfs(y);
 52     }
 53 }
 54 
 55 struct newedge{
 56     int v,nxt;
 57 }newe[MAXN*2];
 58 int newhead[MAXN],newcnt;
 59 void newadd(int x,int y) {
 60     newe[++newcnt].v=y;
 61     newe[newcnt].nxt=newhead[x];
 62     newhead[x]=newcnt;
 63 }
 64 
 65 int main() {
 66     cin>>n>>m;
 67     cnt=1;
 68     for (int i=1,x,y; i<=m; i++) {
 69         cin>>x>>y;
 70         add(x,y),add(y,x);
 71     }
 72     for (int i=1; i<=n; i++) {
 73         if (!dfn[i]) {
 74             tarjan(i,0);
 75         }
 76     }
 77     for (int i=1;i<=n;i++) {
 78         if (!c[i]) {
 79             ++dcc;
 80             dfs(i);
 81         }
 82     }
 83     for (int i=2; i<cnt; i+=2) {
 84         if (qiao[i]) {
 85             cout<<e[i^1].v<<" "<<e[i].v<<"是桥"<<endl;
 86         }
 87     }
 88     cout<<endl;
 89     cout<<"边双联通块有"<<dcc<<""<<endl;
 90     for (int i=1;i<=n;i++) {
 91         cout<<i<<" "<<"belongs"<<" "<<c[i]<<endl;
 92     }
 93     newcnt=1;
 94     for (int i=2;i<=cnt;i++) {
 95         int x=e[i^1].v,y=e[i].v;
 96         if (c[x]==c[y]) continue;
 97         newadd(c[x],c[y]);
 98     }
 99     cout<<"缩点后点数"<<dcc<<" 边数"<<newcnt/2<<endl;
100     for (int i=2;i<newcnt;i++) {
101         cout<<newe[i^1].v<<" "<<newe[i].v<<"是一条边"<<endl;
102     }
103     return 0;
104 }
105 
106 /*
107 12 15
108 1 2
109 1 3
110 2 3
111 2 4
112 3 5
113 4 5
114 1 6
115 6 7
116 6 8
117 7 8
118 7 9
119 7 10
120 10 11
121 10 12
122 11 12
123 */


 

下面是割点

#include <cstdio>
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define pb push_back
#define MAXN 100001
struct edge {
    int v,nxt;
} e[MAXN*2];
int head[MAXN];
bool cut[MAXN];
int dfn[MAXN],low[MAXN];
int n,m,cnt,num,root;
vector <int> dcc[MAXN];
int ccnt;//用于存dcc数组 
//dcc[i]保存编号为i的点双联通块内全部节点
int s[MAXN],top;//
int c[MAXN];
//c[i]表示表示i所属v-DCC编号 
void add(int x,int y) {
    e[++cnt].v=y,e[cnt].nxt=head[x],head[x]=cnt;
}
void tarjan(int x) {
    dfn[x]=low[x]=++num;
    s[++top]=x;
    if (x!=root&&head[x]==0) {
        dcc[++ccnt].pb(x);
        return;
    }
    int flag=0;
    for (int i=head[x]; i; i=e[i].nxt) {
        int y=e[i].v;
        if (!dfn[y]) {
            tarjan(y);
            low[x]=min(low[x],low[y]);
            if (low[y]>=dfn[x]) {
                flag++;
                if (x!=root||flag>1) {
                    cut[x]=1;
                }
                ccnt++;
                int z;
                do{
                    z=s[top--];
                    dcc[ccnt].pb(z);
                }while(z!=y);
                dcc[ccnt].pb(x);
            }
        } 
        else low[x]=min(low[x],dfn[y]);
    }
}

struct newedge{
    int v,nxt;
}newe[MAXN*2];
int newhead[MAXN],tc;
int new_id[MAXN];
void newadd(int x,int y) {
    newe[++tc].v=y;
    newe[tc].nxt=newhead[x];
    newhead[x]=tc;
}

int main() {
    cin>>n>>m;
    cnt=1;
    for (int i=1,x,y; i<=m; i++) {
        cin>>x>>y;
        if (x==y) continue;
        add(x,y),add(y,x);
    }
    for (int i=1; i<=n; i++) {
        if (!dfn[i]) {
            root=i;
            tarjan(i);
        }
    }
    for (int i=1; i<=n; i++) {
        if (cut[i]) {
            cout<<i<<" ";
        }
    }  
    cout<<"是个割点"<<endl;
    for (int i=1;i<=ccnt;i++) {
        cout<<"v-DCC "<<i<<" : ";
        for (int j=0;j<dcc[i].size();j++) {
            cout<<" "<<dcc[i][j];
        }
        cout<<endl;
    }
    num=ccnt;
    for (int i=1;i<=n;i++) {
        if (cut[i]) new_id[i]=++num;
    }
    tc=1;
    for (int i=1;i<=ccnt;i++) {
        for (int j=0;j<dcc[i].size();j++) {
            int x=dcc[i][j];
            if (cut[x]) {
                newadd(i,new_id[x]);
                newadd(new_id[x],i);
            } 
            else c[x]=i;
        }
    }
    cout<<"缩点后森林点数 "<<num<<" 边数 "<<tc/2<<endl;
    printf("编号 1~%d 的为原图v-DCC,编号 >%d 的为原图割点\n",ccnt,ccnt);
    for (int i=2;i<tc;i+=2) {
        cout<<newe[i^1].v<<" "<<newe[i].v<<endl;
    } 
    
    return 0;
}

/*
12 15
1 2
1 3
2 3
2 4
3 5
4 5
1 6
6 7
6 8
7 8
7 9
7 10
10 11
10 12
11 12
*/

/*
8 11
1 2
1 5
2 5
2 3
3 4
4 5
1 6
6 7
6 8
6 9
8 9

*/

 

转载于:https://www.cnblogs.com/codemaker-li/p/9800832.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值