Tarjan算法求割点和割边

目录

名词解释

Tarjan算法

割点求解:

割边求解:

参考博客


名词解释

割点:在无向图中,删除某个节点后,图的连通分量数量增加,则称该节点为割点

桥:如果删除某条边后,连通图变得不再连通,则此条边为桥,或者为割边

Tarjan算法

在Tarjan算法中,有两个十分重要的数组,dfn数组,low数组

dfn数组:表示dfs遍历到该节点的序号,也就是顺序值

low数组:表示当前顶点不通过父亲节点能访问到的祖先节点(父亲节点上面的节点)中的最小顺序值

割点求解:

如果,至少存在一个儿子节点必须要经过父亲节点才能访问到祖先节点,那么这个父亲节点即为割点,假设父亲节点为u,儿子节点为v,那么满足:low[v] >= dfn[u] 说明:节点u为割点,但是仍然存在一种情况,当u为根节点时,所有儿子节点的low[v] 一定满足大于等于dfn[u],所以我们必须要分开讨论:如果,根节点必须要有两个儿子节点,就可以说明跟节点为割点

割边求解:

相同,割边的话,儿子节点不经过这条边就可以访问到祖先节点,那么就要满足:low[v] > dfn[u],如果low[v] == dfn[u],节点v还可以通过其他路径可以回到u,但是只包含条件low[x] > dfn[u]时,说明没有任何一条路可以出了u-v边外,由u到达v,此时说明,u-v之间的边为一条割边

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;
typedef long long ll;
const int maxn = 10000;
int low[maxn],dfn[maxn],head[maxn];
int n,m,tot,k,root;
bool flag[maxn];
vector<pair<int,int> > bridge;
struct Node
{
    int next,v;
}edge[maxn];

void Add_edge(int x,int y)
{
    edge[k].v = y;edge[k].next = head[x];head[x] = k++;
    edge[k].v = x;edge[k].next = head[y];head[y] = k++;
}

void Tarjan(int x,int father)
{
    int child = 0;
    dfn[x] = low[x] = ++tot;
    for(int i = head[x];i != -1;i = edge[i].next)
    {
        int v = edge[i].v;
        if(!dfn[v])
        {
            child ++;
            Tarjan(v,x);
            low[x] = min(low[x],low[v]);
            if(x != root && dfn[x] <= low[v]) flag[x] = 1;    //表示当前节点为割点
            if(x == root  && child == 2) flag[x] = 1;
            if(low[v] > dfn[x]) bridge.push_back(make_pair(x,v));
        }
        else if(v != father)
            low[x] = min(dfn[v],low[x]);
    }
}
int main()
{
    memset(head,-1,sizeof(head));
    int x,y;
    scanf("%d%d",&n,&m);
    for(int i = 0;i < m;i ++)
    {
        scanf("%d%d",&x,&y);
        Add_edge(x,y);
    }
    root = 1;         //在求解割点、割边的时候首先确保图为连通图
    Tarjan(1,root);
    printf("图中的割点为:\n");
    for(int i  = 1;i <= n ;i ++)
        if(flag[i])
            printf("%d ",i);
    printf("\n");
    printf("图中的割边为:\n");
    for(int i = 0;i < bridge.size();i ++)
        printf("%d -- %d\n",bridge[i].first,bridge[i].second);
    printf("\n");
    return 0;
}
/*
6 7
1 4
1 3
4 2
3 2
2 5
2 6
5 6
图中的割点为:
2
图中的割边为:

*/

参考博客

https://blog.csdn.net/wtyvhreal/article/details/43530613

猜你喜欢

转载自blog.csdn.net/li1615882553/article/details/84678722
今日推荐