无向图双连通分量 模板

//点-双连通分量模板。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
using namespace std;
struct Edge
{
    int u,v;
};//u,v是边的两个端点
const int maxn=100005;
int n,m;
int pre[maxn],iscut[maxn],bccno[maxn],dfs_clock,bcc_cnt;
//pre[i]记录i点的编号,iscut[i]标记i点是不是割点,bccno[i]记录i点所属的双连通分量
//bcc_cnt,双联通分量计数器
vector<int>G[maxn],bcc[maxn];//G存原图,bcc[i]存第i个连通分量中的点
stack<Edge>s;
int dfs(int u,int fa)//u和u的父亲
{
    int lowu=pre[u]=++dfs_clock;
    int child=0;
    for(int i=0;i<(int)G[u].size();i++){
        int v=G[u][i];
        Edge e=(Edge){u,v};
        if(!pre[v]){//没有访问过v
            s.push(e);
            child++;
            int lowv=dfs(v,u);
            lowu=min(lowu,lowv);//用后代的low函数更新自己
            if(lowv>=pre[u]){
                iscut[u]=true;
                bcc_cnt++;  //bcc从1开始编号
                bcc[bcc_cnt].clear();
                for(;;){
                    Edge x=s.top();
                    s.pop();
                    if(bccno[x.u]!=bcc_cnt) {bcc[bcc_cnt].push_back(x.u);bccno[x.u]=bcc_cnt;}
                    if(bccno[x.v]!=bcc_cnt) {bcc[bcc_cnt].push_back(x.v);bccno[x.v]=bcc_cnt;}
                    if(x.u==u&&x.v==v) break;
                }
            }
        }
        else if(pre[v]<pre[u]&&v!=fa){
            s.push(e);
            lowu=min(lowu,pre[v]);//用反向边更新自己
        }
    }
    if(fa<0&&child==1) iscut[u]=0;
    return lowu;
}
void find_bcc()
{
    //调用结束后s保证为空,所以不用清空
    memset(pre,0,sizeof(pre));
    memset(iscut,0,sizeof(iscut));
    memset(bccno,0,sizeof(bccno));
    dfs_clock=bcc_cnt=0;
    for(int i=0;i<n;i++)
        if(!pre[i]) dfs(i,-1);
}
int main()
{
    /*
    int a,b;
    cin>>n>>m;
    for(int i=0;i<m;i++){
        cin>>a>>b;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    find_bcc();
    for(int i=0;i<n;i++){
        cout<<bccno[i]<<endl;
    }
    for(int i=1;i<=bcc_cnt;i++){
        for(int j=0;j<(int)bcc[i].size();j++){
            cout<<bcc[i][j]<<" ";
        }
        cout<<endl;
    }
    for(int i=0;i<n;i++) cout<<iscut[i]<<endl;
    */
    return 0;
}
时间: 2024-08-05 18:01:14

无向图双连通分量 模板的相关文章

点-双连通分量模板

by:白书 #define M 10000 int pre[M],dfs_clock,iscut[M],low[M],bcc_cnt,bccno[M]; vector<int>G[M],bcc[M]; struct Edge { int u,v; Edge(int from,int to) { u=from; v=to; } }; stack<Edge> S; int dfs(int u,int fa) { int lowu=pre[u]=++dfs_clock; int chil

图论--无向图点双连通分量模板

对于一个无向图,如果一个点集,它内部的任意一个点对之间,至少有两条点完全不重复的路径,那么这个点集就是原图的一个点双连通分量,而点双联通分量之间是由割点隔开,割点就是如果删去这个点,原图的连通块数会增加,那么这个点就是割点. 通过tarjan算法,我们可以用一次 dfs 标记出所有的割点以及所有双连通分量. 注释版: 1 #include<stdio.h> 2 #include<string.h> 3 #include<stack> 4 #include<algo

LA 5135 井下矿工(点—双连通分量模板题)

https://vjudge.net/problem/UVALive-5135 题意:在一个无向图上选择尽量少的点涂黑,使得任意删除一个点后,每个连通分量至少有一个黑点. 思路: 首先dfs遍历求出割顶和双连通分量,并把每个连通分量保存下来. 接下来分情况讨论: 如果一个点—双连通分量只有一个割顶,在该分量中必须将一个非割顶涂黑. 如果一个点—双连通分量有2个及以上的割顶,不需要涂黑. 如果整个图没有割顶,则至少需要涂黑两个点.(因为有可能删除的就是涂黑的点) 1 #include<iostre

hihoCoder #1184 : 连通性二&#183;边的双连通分量(边的双连通分量模板)

#1184 : 连通性二·边的双连通分量 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在基本的网络搭建完成后,学校为了方便管理还需要对所有的服务器进行编组,网络所的老师找到了小Hi和小Ho,希望他俩帮忙. 老师告诉小Hi和小Ho:根据现在网络的情况,我们要将服务器进行分组,对于同一个组的服务器,应当满足:当组内任意一个连接断开之后,不会影响组内服务器的连通性.在满足以上条件下,每个组内的服务器数量越多越好. 比如下面这个例子,一共有6个服务器和7条连接: 其中包

hihoCoder #1190 : 连通性&#183;四(点的双连通分量模板)

时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho从约翰家回到学校时,网络所的老师又找到了小Hi和小Ho. 老师告诉小Hi和小Ho:之前的分组出了点问题,当服务器(上次是连接)发生宕机的时候,在同一组的服务器有可能连接不上,所以他们希望重新进行一次分组.这一次老师希望对连接进行分组,并把一个组内的所有连接关联的服务器也视为这个组内的服务器(注意一个服务器可能属于多个组). 这一次的条件是对于同一个组满足:当组内任意一个服务器宕机之后,不会影响组内其他服务

poj 3177 &amp; 3352 【无向图双连通分量Tarjan】

题目:poj 3177 & 3352 题意:大概意思就是给你一个无向图,让你添加最少的边,让所有点都双连通. 分析:双连通的定义就是任意两个点至少有两条路可达. 其实做法跟添加最少边强连通一样,先对图中已经双连通的缩点,然后重新编号. 这就是著名的Tanjan算法. 通过搜索的思想对所有存在环的边遍相同的号 如果要让所有的点双连通,那么对于缩点后的图中如果度数为 1 的话,这些边肯定要连接到其他的点才能双连通,而题目要求添加最少,所以连接到其他度数也为 1 的点是最优的,那么答案就是(odd+1

UVA5135 Mining Your Own Business ( 无向图双连通分量)

题目链接 题意:n条隧道由一些点连接而成,其中每条隧道链接两个连接点.任意两个连接点之间最多只有一条隧道.任务就是在这些连接点中,安装尽量少的太平井和逃生装置,使得不管哪个连接点倒塌,工人都能从其他太平井逃脱,求最少安装数量和方案. 分析:本题相当于在一张无向图上选择尽量少的点涂黑(对应太平井),使任意一个点被删除后,每个连通分量都至少还有一个黑点.不同的连通分量最多有一个公共点即割点,将割点涂上是不划算的,因为删除割点后,要保证每个连通分量还要有黑点,所以还要在其他的连通分量中涂黑点,如果不涂

双连通分量模板

点双: 1 void dfs(int u,int fa){ 2 dfn[u]=low[u]=++idx,stack[++top]=u; 3 for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) 4 if (!dfn[v]) dfs(v,u),low[u]=min(low[u],low[v]); 5 else if (v!=fa) low[u]=min(low[u],dfn[v]); 6 if (dfn[u]==low[u]) top--; // fa-u

Tarjan求点双连通分量

概述 在一个无向图中,若任意两点间至少存在两条"点不重复"的路径,则说这个图是点双连通的(简称双连通,biconnected) 在一个无向图中,点双连通的极大子图称为点双连通分量(简称双连通分量,Biconnected Component,BCC) 性质 任意两点间至少存在两条点不重复的路径等价于图中删去任意一个点都不会改变图的连通性,即BCC中无割点 若BCC间有公共点,则公共点为原图的割点 无向连通图中割点一定属于至少两个BCC,非割点只属于一个BCC 算法 在Tarjan过程中维