tarjan算法 求割点

点双连通分量:在一个无向图中,存在一个极大子图,删除任意一个节点之后该图仍然是一个连通图。

割点:在一个无向图中,存在一个节点,删除这个节点之后,该无向图会被分为若干个连通图(个数大于一),则该点为割点。

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#define ll long long
#define pb push_back
#define fi first
#define se second

const int N = 2e4 + 10;
int dfn[N]; //时间戳
int low[N]; //能到达最早点
int cut[N]; //是否是割点
vector<int > E[N]; //
int tim;//dfs序号
int root; //每个连通图的出发点
int cut_cnt; //割点数量
int n, m; //点数  边数


//时间复杂度  O(m)
//割点条件
//(1)该点为最初点root,且该点之下至少存在左图和右图
//(2)该点不u为root,但是该点之后的点无法到达u之前的点

void init(int n){
    for(int i = 1; i <= n; ++i){
        dfn[i] = low[i] = 0;
        cut[i] = 0;
        E[i].clear();
    }
    tim = cut_cnt = 0;
}

void tarjan(int now, int pre){
    dfn[now] = low[now] = ++tim;

    int son = 0;//图个数
    for(auto to : E[now]){
        
        if(to == pre) continue;

        if(!dfn[to]){
            ++son;
            tarjan(to, now);
            low[now] = min(low[now], low[to]);
            //(2)该点不u为root,但是该点之后的点无法到达u之前的点
            if(now != root && dfn[now] <= low[to]) cut[now] = 1;
        }else low[now] = min(low[now], dfn[to]);
    }

    //(1)该点为最初点root,且该点之下至少存在左图和右图
    if(now == root && son > 1) cut[now] = 1;
}

void show_info(){

    //割点数量
    printf("\ncut point 's number = %d\n", cut_cnt);
    //割点信息
    printf("they' re : ");
    for(int i = 1; i <= n; ++i){
        if(cut[i]) printf("(%d) ", i);
    }
    printf("\n\n");
}


void solve(){

    while(~scanf("%d%d", &n, &m)){
        //scanf("%d%d", &n, &m);
        //初始化每组数据
        init(n);
        
        //读边
        for(int i = 1; i <= m; ++i){
            int u, v;
            scanf("%d%d", &u, &v);
            E[u].pb(v);
            E[v].pb(u);
        }

        //可能不是一个连通图
        for(int now = 1; now <= n; ++now){
            if(!dfn[now]){
                root = now;
                //这样可以防止自环的情况
                tarjan(now, now);
            }
        }
        //统计割点个数
        for(int i = 1; i <= n; ++i){
            if(cut[i]) ++cut_cnt;
        }
        show_info();
    }
}

int main(){
    
    solve();    
    //cout << "not error" << endl;
    return 0;
}

 

你可能感兴趣的:(tarjan算法 求割点)