无向图求割顶与桥

无向图求割顶与桥

对于无向图G,如果删除某个点u后,连通分量数目增加,称u为图的关节点或割顶。对于连通图,割顶就是删除之后使图不再连通的点。如果删除边(u,v)一条边,就可以让连通图变成不连通的,那么边(u,v)是

具体的概念和定义比较多,在刘汝佳<<训练指南>>P312-314页都有详细的介绍。

下面来写求无向图割顶和桥的DFS函数.我们令pre[i]表示第一次访问i点的时间戳,令low[i]表示i节点及其后代所能连回(通过反向边)的最早祖先的pre值.

下面的dfs函数返回的是当前遍历的节点u的low值.如果u是割顶还会标记u节点.且如果u->v(v是u的儿子节点)边是桥也会标记该边.

//求无向图的割顶和桥

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=100000+10;
int n,m;
int dfs_clock;//时钟,每访问一个节点增1
vector<int> G[maxn];//G[i]表示i节点邻接的所有节点
int pre[maxn];//pre[i]表示i节点被第一次访问到的时间戳,若pre[i]==0表示i还未被访问
int low[maxn];//low[i]表示i节点及其后代能通过反向边连回的最早的祖先的pre值
bool iscut[maxn];//标记i节点是不是一个割点

//求出以u为根节点(u在DFS树中的父节点是fa)的树的所有割顶和桥
//初始调用为dfs(root,-1);
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])
        {
            child++;//未访问过的节点才能算是u的孩子
            int lowv=dfs(v,u);
            lowu=min(lowu,lowv);
            if(lowv>=pre[u])
            {
                iscut[u]=true;      //u点是割顶
                if(lowv>pre[u])   //(u,v)边是桥
                    printf("边(%d, %d)是桥\n",u,v);
            }
        }
        else if(pre[v]<pre[u] && v!=fa)//v!=fa确保了(u,v)是从u到v的反向边
        {
            lowu=min(lowu,pre[v]);
        }
    }
    if(fa<0 && child==1 )
        iscut[u]=false;//u若是根且孩子数<=1,那u就不是割顶
    return low[u]=lowu;
}

int main()
{
    while(scanf("%d%d",&n,&m)==2&&n)
    {
        dfs_clock=0;//初始化时钟
        memset(pre,0,sizeof(pre));
        memset(iscut,0,sizeof(iscut));
        for(int i=0;i<n;i++) G[i].clear();
        for(int i=0;i<m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs(0,-1);//初始调用
        for(int i=0;i<n;i++)if(iscut[i]==true)
            printf("割顶是:%d\n",i);
    }
    return 0;
}

删除一个无向图中的点,能使得原图增加几个连通分量呢?

如果该点是一个孤立的点,那么增加-1个。

如果该点不是割点,那么增加0个。

如果该点是割点且非根节点,那么增加该点在dfs树中(无反向边连回早期祖先的)的儿子数。

如果该点是割点且是一个dfs树的根节点,那么增加该点在dfs树中(无反向边连回早期祖先的)的儿子数-1的数目。

基本应用

POJ 1144 Network(简单求无向图割顶数):直接求割顶数。解题报告!

POJ 2117 Electricity(无向图割点):问删除一点能增加几个连通分量。解题报告!

POJ 1523 SPF(割点所割连通分量数): 问删除一点能增加几个连通分量。解题报告!

HDU 4587 TWO NODES(无向图割点):还是关于删除一个点能剩余几个连通分量的问题。解题报告!

HDU 3849 By Recognizing…(求无向图的桥数目):如何在dfs完之后判断一条边是否是桥?解题报告!

HDU 4738 Caocao‘s Bridges(重边无向图求桥):有重边的无向图如何求桥边?解题报告!

时间: 2024-10-06 15:35:53

无向图求割顶与桥的相关文章

无向图求割顶和桥总结

1.求能够分成几个联通分量什么的一般都在dfs中间那里if(...>...) cnt[i],iscut[i]维护一下就OK了. 2.根结点特别需要注意. 好像就没了→_→

无向图的割顶和桥

割顶: 关键点,删掉这个点后,图的连通分量 + 1: 桥: 在割顶的基础上,发现删除 (u,v) 这条边,图就变成非连通的了. 如何找出所有割顶和桥: 时间戳: 在无向图的基础上,DFS建树的过程中,各点进栈和出栈的时间 dfs_clock,进栈的时间 pre[],出栈的时间 post[] 在DFS程序中的体现就是: void previst(int u) { pre[u]= ++dfs_clock; } void postvist(int u) { post[u] = ++dfs_clock;

连通分量 无向图的割顶和桥 无向图的双连通分量 有向图的强连通分量

时间戳 dfs_clock :说白了就是记录下访问每个结点的次序.假设我们用 pre 保存,那么如果 pre[u] > pre[v], 那么就可以知道先访问的 v ,后访问的 u . 现在给定一条边, (u, v), 且 u 的祖先为 fa, 如果有 pre[v] < pre[u] && v != fa, 那么 (u, v) 为一条反向边. 1 求连通分量: 相互可达的节点称为一个连通分量: #include <iostream> #include <cstd

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

https://blog.csdn.net/stillxjy/article/details/70176689 割顶和桥:对于无向图G,如果删除某个节点u后,连通分量数目增加,则称u为图的割顶:如果删除某条边后,连通分量数目增加,则称该边为图的桥.对于连通图删除割顶或桥后都会使得图不再连通 以下我,我们利用dfs的性质来快速找出一个连通图中的所有的割顶和桥 首先我们要引入”时间戳”这个概念: 时间戳:表示在进行dfs时,每个节点被访问的先后顺序.每个节点会被标记两次,分别用pre[],和post

UVA 315 :Network (无向图求割顶)

题目链接 题意:求所给无向图中一共有多少个割顶 用的lrj训练指南P314的模板 #include<bits/stdc++.h> using namespace std; typedef long long LL; const int N=109; struct Edge { int to,next; Edge(){} Edge(int _to,int _next) { to=_to; next=_next; } }edge[N*N*2]; int head[N]; int dfn[N],lo

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

割顶:对于无向图G,如果删除某个点u后,连通分量的数目增加, 称u为图的割顶.对于连通图,割顶就是删除之后使图不再连通的点. 割顶的求解依如下定理: 在无向连通图G的DFS树中,非根结点u是G的割顶当且仅当u存在一个子节点v,使得v及其所有后代都没有反向边连回u的祖先(连回u)不算. 算法实现: 采用时间戳,在dfs遍历的过程中给每个节点u均标记以前序时间戳pre[u],设low[u]为u及其后代所能连回的最早的祖先的pre值,则定理中的条件就可以简写成结点u存在一个子结点v,使得 low[v]

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

#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N = 250; int head[N], low[N], dfn[N], fa[N]; int n, m, now = 1, Tarjan_clock; bool is_cut[N]; struct Node{ int u, v, nxt; }E[N]; inline int read()

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

一.dfs框架: 1 vector<int>G[maxn]; //存图 2 int vis[maxn]; //节点访问标记 3 void dfs(int u) 4 { 5 vis[u] = 1; 6 PREVISIT(u); //访问节点u之前的操作 7 int d = G[u].size(); 8 for(int i = 0; i < d; i++)//枚举每条边 9 { 10 int v = G[u][i]; 11 if(!vis[v])dfs(v); 12 } 13 POSTVIS

无向图的割顶和桥(tarjan模板)

#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define maxn 7500 #define inf 0x3f3f3f3f int first[maxn],to[maxn],nxt[maxn],e; int pre[maxn],low[maxn]; int clock; int iscut[maxn]; void