图论1--连通性问题的整理

试着用一段代码解决图论的几个基本的连通性问题:

关键词:DFS,Tarjan,邻接表

  1. 全图连通分量,是否有,有的话,求个数
  2. 求关节点/割点并输出其贡献连通分量个数
  3. 求桥,并按照顺序输出
  4. 强连通域分解并输出:Tarjan ,//也可用Kosaraju算法
  5. 边双连通分支:有桥的连通图G,增加最少的边,构造成双连通图;

 

代码如下:

//
//  main.cpp
//  图论-连通问题整理
//
//  Created by Cordelia.LIU on 2019/11/6.
//  Copyright © 2019 Cordelia.LIU All rights reserved.
//



/*一个综合的图的连通问题
 1.关键
    1)求割点
            dfs/是关节点判断的两个条件:1)独子根,if(u==root&&son>1) u是关节点
                                2)非根的最高祖先 ,uv是树边(就是父子关系)low[v]>=dfs[u];u是关节点
    2)求割边
            uv是树边(就是父子关系)low[v]>dfs[u];
    3)求一共几个连通域
            在函数上层设,上层的dfs几次就有几个连通域
    4)求删掉每个点后增加的连通域块(if 关节点+1,ifnot 不加)
    
 
 2.技巧
    1)存图的技巧 addedge 1)检查重变2)快速遍历
    2)几个重要的数组 dfs[]. low[]
    3) 求割边的时候有时候要检查重边 //
        重边编号
 
 */



#include 
#include 
#include
#include 
#include 
using namespace std;

const int MAX=100;
int dfs[MAX];//存点在dfs中的编号,相当于dtime
int low[MAX]; //语义是节点i以及i的子孙,通过非父亲节点能访问到的最高的祖先,随着dfs不断更新
int from[MAX];//存树边的来边,也就是父亲;
int bridge;//存桥的数量
int add_block[MAX];//删除某个节点之后,令全图连通域增加多少
int total;//记录边的总数;
int depth;//记录当前的遍历深度
int cnt;//一共几个连通域
int articucount;//一个关节点
int degree[MAX];//存每个边双连通分量凝缩成点后度数(1桥,+1度)
int block[MAX];//每个双连通分量包含的桥数;(要通过关节点双连通域分解去求,见任务4)
vector > component;//存放一组组连通域'
vector cuts;//存放割点集

int head[MAX];//存边e在的顶点a,一共有的邻边个数,next始终比其在head中少1;
stack s;



struct Edge {
    int a;
    int b;//a是起点,b是终点,
    int next; //邻边的编号索引
    bool cut;//标记是不是割点
    Edge():next(-1),cut(0){};//注意初始化
    Edge(int a,int b,int id):next(-1),cut(0){};//id初始化都为-1,这样遍历的时候检查id==-1就可以知道是不是有没有边了
    //处理方法2是存edges存Edge*, 初始化成NULL,检查是NULL就说明没有边;
    bool operator<(const Edge&e)const{
        return a"< bridges;



void init(){//和测试case有关的应该在这一层初始化,和内部实现有关的应该在内层初始化
    memset(dfs,-1,sizeof(dfs));//dfs初始化为-1.这样-1就可以检查是否被访问
    memset(head,-1,sizeof(head));//这样第一个的next才会是-1
    memset(add_block,0,sizeof(add_block));
    memset(degree,0,sizeof(degree));
    memset(block,0,sizeof(block));
    for(int i=0;i=dfs[u]){//割点判断;
                cuts.push_back(u);
                add_block[u]++;
                articucount++;
                    
            }
            if(low[v]>dfs[u]){
                bridge++;//此边为割桥
                edges[i].cut=true;
                if(u1){//如果u是根且有多于1的分支
            cuts.push_back(u);
            add_block[u]=son-1;//⚠️问什么是son-1 ,因为语义是增加的块,
        }
    
    }
}

void solve(int N){//解决有N的顶点的问题;
    init();
    for(int i=0;i叶节点判断->(leaf+1)/2
    for(int i=0;i>T;
        while(T--){
            int N,a,b;
            cin>>N;
            while(cin>>a>>b){
                addedge(a,b);
                addedge(b,a);//无向图
            //假设编号都是从0开始
            }
            solve(N);
        }
        

    return 0;
}

 

你可能感兴趣的:(图论1--连通性问题的整理)