/*
    Name: 图的割点(边表集实现)
    Copyright: 
    Author: 巧若拙 
    Date: 20-11-14 21:17
    Description: 
    在一个无向连通图中。假设有一个顶点集合,删除这个顶点集合。以及这个集合中全部顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合。
求割点与桥的算法是R.Tarjan发明的。对图深度优先搜索。定义DFS(u)为u在搜索树(下面简称为树)中被遍历到的次序号(等价于时间戳)。
定义Low(u)为u或u的子树中能通过非父子边追溯到的最早的节点。即DFS序号最小的节点的序号。

依据定义,则有:  
Low(u)=Min { DFS(u) ,DFS(v)},当中 (u,v)为后向边(返祖边) 等价于 DFS(v)<DFS(u)且v不为u的父亲节点 Low(v) (u,v)为树枝边(父子边) 
一个顶点u是割点。当且仅当满足(1)或(2) :
(1) u为树根。且u有多于一个子树。 
(2) u不为树根。且满足存在(u,v)为树枝边(或称父子边,即u为v在搜索树中的父亲),使得DFS(u)<=Low(v)。

本文用边表集存储图的信息,实现了递归和非递归两种算法。

*/
#include<stdio.h>
#include<stdlib.h>

#define MAXN 26   //最大变量(顶点)数量 
#define MAXM 100000   //最大关系式数量

typedef char VertexType; //顶点类型由用户自己定义
typedef int EdgeType; //边上的权值类型由用户自己定义

typedef struct Edge{ //边集数组 
    int u, v; //弧尾和弧头 
    int next; //指向同一个弧尾的下一条边 
//    EdgeType weight; //权值,对于非网图能够不须要 
} EdgeLib;

EdgeLib edge[MAXM]; //存储边信息
int first[MAXN]; //指向顶点的第一条边
int flag[MAXN] = {0}; //存储顶点是否为割点 
int num[MAXN] = {0}; //存储顶点的时间戳信息 
int low[MAXN] = {0}; //存储顶点的最小时间戳信息 
int index = 0; //用来进行时间戳的递增

void CreateGraph(int n, int m);//创建一个图
void PrintGraph(int n, int m);//输出图
void CutPoint_DFS(int root, int cur, int father);//採用深度优先搜索寻找割点(递归算法) 
void CutPoint(int root, int n);//採用深度优先搜索寻找割点(非递归算法)

int main()
{
    int i, m, n;
    
    printf("请输入顶点数量和边数量:\n"); 
    scanf("%d%d", &n, &m);    
    
    CreateGraph(n, m);//创建一个图
    PrintGraph(n, m);//输出图
    
 //   CutPoint_DFS(0, 0, 0);//从0号顶点開始深度优先搜索寻找割点(递归算法) 
    CutPoint(0, n);

printf("\n割点为:"); 
    for (i=0; i<n; i++)//输出全部割点
    {
        if (flag[i] == 1)
            printf("%d ", i);
    } 
    printf("\n");
    
    return 0;
}

void CreateGraph(int n, int m)//创建一个图
{
    int i;
    
    for (i=0; i<n; i++)//初始化图 
    {
        first[i] = -1;
        num[i] = low[i] = flag[i] = 0;
    }
    
    for (i=0; i<m+m; i+=2)  //读入边信息(注意是无向图) 
    {
        scanf("%d%d", &edge[i].u, &edge[i].v);
        edge[i].next = first[edge[i].u];
        first[edge[i].u] = i;
        
        edge[i+1].u = edge[i].v;
        edge[i+1].v = edge[i].u;
        edge[i+1].next = first[edge[i+1].u];
        first[edge[i+1].u] = i + 1;
    }
}

void PrintGraph(int n, int m)//输出图
{
    int i, j;
    
    for (i=0; i<n; i++)
    {
        printf("%d: ", i);
        j = first[i]; //指向i的第一条边 
        while (j != -1)
        {
            printf("<%d, %d>, ", edge[j].u, edge[j].v);
            j = edge[j].next; //指向下一条边 
        }
        printf("\n");
    }
    printf("\n");
}

void CutPoint_DFS(int root, int cur, int father)//採用深度优先搜索寻找割点(递归算法) 
{
    int k, child = 0;
    
    num[cur] = low[cur] = ++index;
    k = first[cur];
    while (k != -1)
    {
        if (num[edge[k].v] == 0) //新结点做儿子
        {
            child++;
            CutPoint_DFS(root, edge[k].v, cur);
            
            low[cur] = (low[cur] < low[edge[k].v]) ? low[cur] : low[edge[k].v];//取最小值 
            
            if ((cur != root && num[cur] <= low[edge[k].v])
             || (cur == root && child == 2))
            {
                flag[cur] = 1;
            }
        } 
        else if (edge[k].v != father) //与旁系祖先有连接,事实上也能够不加这个限制条件,由于假设父亲是自己则low[cur]值不变 
        {
            low[cur] = (low[cur] < num[edge[k].v]) ?

low[cur] : num[edge[k].v];//取最小值 
        } 
        
        k = edge[k].next;
    }
}

void CutPoint(int root, int n)//採用深度优先搜索寻找割点(非递归算法) 
{
    int Stack[MAXN]; //用来存储当前被处理顶点的栈 
    int SF[MAXN]; //指向顶点的第一条未搜索边
    int child[MAXN] = {0}; //存储顶点的儿子数量 
    int k, u, v, top = 0;
    
    for (u=0; u<n; u++)//初始化SF 
        SF[u] = first[u];
        
    Stack[top] = root;
    num[root] = low[root] = ++index;
    while (top >= 0)
    {
        k = SF[Stack[top]];
        if (k != -1)
        {
        SF[Stack[top]] = edge[k].next; //指向下一条边 
            if (num[edge[k].v] == 0)
            {
                child[Stack[top]]++;
                Stack[++top] = edge[k].v;
                low[edge[k].v] = num[edge[k].v] = ++index;
            }
            else
            {
                low[Stack[top]] = (low[Stack[top]] < num[edge[k].v]) ? low[Stack[top]] : num[edge[k].v];//取最小值
            }
        }
        else
        {
            if (top > 0)
            {
                u = Stack[top-1];
                v = Stack[top];
                low[u] = (low[u] < low[v]) ? low[u] : low[v];
                if ((u != root && low[v] >= num[u])
                 || (u == root && child[u] == 2))
                {
                    flag[u] = 1;
                }
            }
            top--;
        }
    }        
}

图的割点(边表集实现)相关推荐

  1. 图的割点、桥和双连通分支的基本概念

    点连通度与边连通度 回到正题,首先介绍下什么是图的边连通度和点连通度.一般来说,点连通度是指对应一个图G,对于所有点集U属于V(G),也就是V(G)的子集中,使得G-U要么是一个非连通图,要么就是一个 ...

  2. DSt:数据结构的最强学习路线之数据结构知识讲解与刷题平台、刷题集合、问题为导向的十大类刷题算法(数组和字符串、栈和队列、二叉树、堆实现、图、哈希表、排序和搜索、动态规划/回溯法/递归/贪心/分治)总

    DSt:数据结构的最强学习路线之数据结构知识讲解与刷题平台.刷题集合.问题为导向的十大类刷题算法(数组和字符串.栈和队列.二叉树.堆实现.图.哈希表.排序和搜索.动态规划/回溯法/递归/贪心/分治)总 ...

  3. 图的割点(解释及实现)

    图的割点 1.割点是什么 2.找割点的办法 2.1方法的核心 2.2 具体过程 2.3实现 1.割点是什么 在一个无向连通图中,如果删除某个顶点后,图不再连通(任意两顶点之间不能相互到达),我们称这样 ...

  4. 20 求图的割点和割边—Tarjan算法

    1 图的割点 问题描述 去掉2号城市,这样剩下的城市之间就不能两两相互到达.例如4号城市不能到5号城市,6号城市也不能到达1号城市等等. 下面将问题抽象化.在一个无向连通图中,如果删除某个顶点后,图不 ...

  5. 001.Tarjan算法:求解图的割点与桥(割边)

    简介: 割边和割点的定义仅限于无向图中.我们可以通过定义以蛮力方式求解出无向图的所有割点和割边,但这样的求解方式效率低.Tarjan提出了一种快速求解的方式,通过一次DFS就求解出图中所有的割点和割边 ...

  6. er图转关系模式规则_ER图转换成关系模式集的规则[图]

    ER图转换成关系模式集的规则[图] 08-18栏目:技术 TAG:关系模式 关系模式 转自己博客园文章 www.jhua.org copyright www.jhua.org A与B=1:1 在A表里 ...

  7. 图的割点、桥与双连通分支

    [点连通度与边连通度] 在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合.一个图的点连通度的定义为,最小割点集 ...

  8. [转载]图的割点、桥与双连通分支

    [点连通度与边连通度] 在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合.一个图的点连通度的定义为,最小割点集 ...

  9. 图的割点 图的割边 二分图

    枯木逢春不再茂,年少且惜镜边人 这周准备完结阿哈算法,其中有一章的学习不是很熟练(总之学的慢,忘的快.哎,真的,学完得好好从背包开始复习了,等复习完了,准备进行更深层次的学习,也就是从做题中获取知识, ...

最新文章

  1. oracle jdedward,Oracle JDEdwards EnterpriseOne Tools任意文件上传漏洞(CVE-2011-2317)
  2. 2013科目三道路驾驶技能通用评判标准
  3. 状态空间搜索好题UVA10603
  4. Swift 3必看:新的访问控制fileprivate和open
  5. linux下完全删除mysql
  6. Hive实践(hive0.12)
  7. java爬虫新闻网站_java爬虫 之 搜狐新闻爬虫(一)
  8. 数字日期格式转换yyyymmdd_如何把日期改为yyyymmdd
  9. 第五次作业—— 四则运算“软件”开发
  10. 基于封锁的并发控制机制
  11. PL/SQL 工具远程连接Oracle数据库方法,plsql免安装oracle客户端直接配置oci实战演示
  12. 【ICML2021】 9篇RL论文作者汪昭然:构建“元宇宙”和理论基础,让深度强化学习从虚拟走进现实...
  13. 计算机网络习题:应用层
  14. 黑名单电话自动拦截【Android】
  15. D2C-Net: A Dual-branch, Dual-guidance and Cross-refine Network for Camouflaged Object Detection阅读笔记
  16. micro的介绍、安装与使用
  17. lucas定理(学习笔记)
  18. 织梦网站添加优酷腾讯等视频方法
  19. 信息学奥赛一本通 1244:和为给定数 | OpenJudge NOI 1.11 07:和为给定数
  20. JVM-对象什么时候进入老年代(实战篇)

热门文章

  1. 服务幂等以及常用实现方式
  2. Java 理论与实践: 垃圾收集简史
  3. 通俗易懂SpringMVC整体框架理解
  4. 基于内容的图像检索 Database for Content-Based Image Retrieval
  5. 编程之美-最短摘要的生成方法整理
  6. SSH服务如何远程管理RHEL 5
  7. Chromium on Android: 认识Chromium WebView
  8. javabean简述
  9. 分析 H.265 + AAC 的 FLV 文件
  10. 测度论与概率论有什么关系?为什么要学习测度论?