2018/2/11 每日一学 无向图割顶和桥

Posted alex-leaves

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018/2/11 每日一学 无向图割顶和桥相关的知识,希望对你有一定的参考价值。

割顶和桥:对于无向图G,如果删除某个节点u后,连通分量数目增加,则称u为图的割顶;如果删除某条边后,连通分量数目增加,则称该边为图的桥。

对于连通图删除割顶或桥后都会使得图不再连通。

我们利用dfs的性质来快速找出一个连通图中的所有的割顶和桥。

设low[u]为u及其后代所能连回的最早的祖先的pre[]值,pre[]为时间戳则当u存在一个子节点v使得low[v] >= pre[u]时u就为割顶
同理当 low[v] > pre[u]时 u-v为桥

看代码吧(转自http://blog.csdn.net/stillxjy/article/details/70176689)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
using namespace std;

const int maxn = 1000;

int n,m;
vector<int> G[maxn];
int low[maxn],pre[maxn];
int dfs_clock;     //时间戳
int iscut[maxn];   //标记是否为割顶

int dfs(int u,int fa)
{
    int lowu = pre[u] = ++dfs_clock;
    int child = 0;
    for(int i=0;i<G[u].size();i++)
    {
        int v = G[u][i];
        if(!pre[v])     //没有访问的v
        {
            child++;    //孩子节点的数目
            int lowv = dfs(v,u);
            lowu = min(lowu,lowv);    //用后代更新lowu
            if(lowv >= pre[u]) iscut[u] = 1;
            if(lowv > pre[u]) cout<<"桥:"<<u<<"-"<<v<<endl;
        }
        else if(pre[v] < pre[u] && v != fa)  //用反向边更新lowu
        {
            lowu = min(lowu,pre[v]);
        }
    }
    if(fa < 0 && child == 1) iscut[u] = 0;    //对于根节点的处理
    low[u] = lowu;
    return lowu;
}


int main()
{
    freopen("in.txt","r",stdin);
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(pre,0,sizeof(pre));
        memset(iscut,0,sizeof(iscut));
        for(int i=0;i<=n;i++) G[i].clear();
        int u,v;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }

        dfs(1,-1);
        for(int i=1;i<=n;i++) if(iscut[i])
            cout<<i<<endl;
    }
    return 0;
}

 

以上是关于2018/2/11 每日一学 无向图割顶和桥的主要内容,如果未能解决你的问题,请参考以下文章

无向图的割顶和桥,无向图的双连通分量入门详解及模板 -----「转载」

无向图求割顶和桥总结

Tarjan 算法求无向图的割顶和桥

无向图的割顶和桥的性质 以及双连通分量的求解算法

DFS的运用(二分图判定无向图的割顶和桥,双连通分量,有向图的强连通分量)

连通分量专题