基于有向图的邻接矩阵计算其割点、割边、压缩图,并用networkx可视化绘制

news2024/11/25 21:32:24

基于有向图的邻接矩阵计算其割点、割边、压缩图,并用networkx可视化绘制

  • 为什么基于邻接矩阵计算图的割点、割边、压缩图
    • 实现python代码
    • 代码运行效果
    • 结论:

为什么基于邻接矩阵计算图的割点、割边、压缩图

由于矩阵计算过程,被广泛优化;
因此,采用矩阵计算方法实施割点、割边、压缩图的计算,效率高、逻辑简单。

实现python代码

import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
from networkx.drawing.nx_agraph import graphviz_layout

# 有向图的邻接矩阵
M = np.array([
    #1, 2, 3, 4, 5, 6, 7, 8
    [0, 0, 0, 0, 0, 1, 0, 0],   #u1->u6
    [0, 0, 0, 0, 1, 0, 0, 0],   #u2->u5
    [0, 1, 0, 1, 0, 0, 0, 0],   #u3->u2, u3->u4
    [0, 0, 0, 0, 0, 0, 0, 1],   #u4->u8
    [0, 1, 1, 0, 0, 0, 0, 0],   #u5->u2, u5->u3
    [0, 0, 0, 0, 0, 0, 1, 0],   #u6->u7
    [0, 0, 0, 1, 0, 0, 0, 0],   #u7->u4
    [0, 0, 0, 0, 0, 1, 0, 0]    #u8->u6
], int)
print('邻接矩阵:\n', M)
nVerts = M.shape[0]             #顶点个数

# IM = I(单位阵) + M(邻接矩阵)————在邻接矩阵基础上,添加自环结构
IM = np.identity(nVerts, int) + M
# R = ((I + M) ** (n-1) == 1).astype(int),构造可达矩阵
# 矩阵的n次幂——矩阵连乘n次
R = (np.linalg.matrix_power(IM, nVerts - 1) > 0).astype(int)
print('可达矩阵:\n', R)

# 由R * R.T保持对称边,去除非对称边
sR = R * R.T
print('对称矩阵:\n', sR)

# 按对称矩阵sR中的行数据实施分组汇总
rows = [ [''.join(sR[i, :].astype(str)), i] for i in range(nVerts) ]
print('行数组编码组=\n', rows)
grps = {}
for row in rows:
    if row[0] in grps.keys():
        grps[row[0]].append( row[1])
    else:
        grps[row[0]] = [row[1]]
print('按相同编码实施顶点分组结果:\n', grps )
# 计算分组数量
nGroups = len(list(grps.keys()))
print('分组数量=', nGroups)

groupInfo = list(grps.values())
groups = {}
for grpNo, elems in enumerate(groupInfo):
    for elem in elems:
        groups[elem] = grpNo
print('按强连通特性分组的节点组:\n', groups)

# 压缩图的邻接矩阵
compactR = np.zeros((nGroups, nGroups))               
# 遍历邻接矩阵获取组建连接信息
connGroups = {}
for i in range(nVerts):
    for j in range(nVerts):
        if i == j: continue                     #相同顶点关系继续
        if groups[i] == groups[j]: continue     #同组关系继续
        if M[i, j] == 1:                        
            compactR[groups[i], groups[j]] = 1  #记录压缩图中的组间有向边
            cn = (groups[i], groups[j])         #不同组间的连接关系
            if cn in connGroups.keys():
                connGroups[cn] += [(i, j)]
            else:
                connGroups[cn] = [(i, j)] 
print('组间连接关系=\n', connGroups)   

# 根据组间连接关系获取候选割点、割边集合
cutEdges = []       #割边
cutVerts = []       #割点
for key in connGroups.keys():
    vals = connGroups[key]                  
    if len(vals) == 1:
        print('割边', vals)
        cutEdges += vals        #添加割边
        cutVerts += vals[0]     #添加割点

# 根据邻接矩阵计算每个顶点的度数——为真实割点判断提供依据
# 顶点度数=行求和(出度)+ 列求和(入度)
vertDegrees = [np.sum(M[i, :]) + np.sum(M[:, i]) for i in range(nVerts)]
print('顶点度数=\n', vertDegrees)
print('候选割点=\n', cutVerts)
# 筛选掉度=1的候选割点————条件:割点的度数必须 > 1
cutVerts = [v for v in cutVerts if vertDegrees[v] > 1]        
print('割点\n', cutVerts)

# 绘图
plt.figure()
plt.title('Directed graph')
dg = nx.DiGraph()                           #构造有向图
for i in range(nVerts):
    for j in range(nVerts):
        if M[i, j] == 1:
            dg.add_edge(i, j)               #添加有向边
# 智能布局节点位置            
pos = graphviz_layout(dg, prog='dot')       
nx.draw(dg, with_labels = True, pos = pos)  #绘制有向图
# 绘制红色割边
nx.draw_networkx_edges(dg, pos = pos, edgelist=cutEdges, width=1.0, edge_color='r')
# 绘制红色割点
nx.draw_networkx_nodes(dg, pos = pos, nodelist=cutVerts, node_color='r')
plt.show()

# 根据压缩图的邻接矩阵,可绘图压缩图
plt.figure()
plt.title('compact graph')
dg1 = nx.DiGraph()
for i in range(nGroups):
    for j in range(nGroups):
        if compactR[i, j] == 1:
            dg1.add_edge(i, j)
pos1 = graphviz_layout(dg1, prog='dot')       
nx.draw(dg1, with_labels = True, pos = pos)  #绘制有向图
plt.show()

代码运行效果

邻接矩阵:
[[0 0 0 0 0 1 0 0]
[0 0 0 0 1 0 0 0]
[0 1 0 1 0 0 0 0]
[0 0 0 0 0 0 0 1]
[0 1 1 0 0 0 0 0]
[0 0 0 0 0 0 1 0]
[0 0 0 1 0 0 0 0]
[0 0 0 0 0 1 0 0]]
可达矩阵:
[[1 0 0 1 0 1 1 1]
[0 1 1 1 1 1 1 1]
[0 1 1 1 1 1 1 1]
[0 0 0 1 0 1 1 1]
[0 1 1 1 1 1 1 1]
[0 0 0 1 0 1 1 1]
[0 0 0 1 0 1 1 1]
[0 0 0 1 0 1 1 1]]
对称矩阵:
[[1 0 0 0 0 0 0 0]
[0 1 1 0 1 0 0 0]
[0 1 1 0 1 0 0 0]
[0 0 0 1 0 1 1 1]
[0 1 1 0 1 0 0 0]
[0 0 0 1 0 1 1 1]
[0 0 0 1 0 1 1 1]
[0 0 0 1 0 1 1 1]]
行数组编码组=
[[‘10000000’, 0], [‘01101000’, 1], [‘01101000’, 2], [‘00010111’, 3], [‘01101000’, 4], [‘00010111’, 5], [‘00010111’, 6], [‘00010111’, 7]]
按相同编码实施顶点分组结果:
{‘10000000’: [0], ‘01101000’: [1, 2, 4], ‘00010111’: [3, 5, 6, 7]}
分组数量= 3
按强连通特性分组的节点组:
{0: 0, 1: 1, 2: 1, 4: 1, 3: 2, 5: 2, 6: 2, 7: 2}
组间连接关系=
{(0, 2): [(0, 5)], (1, 2): [(2, 3)]}
割边 [(0, 5)]
割边 [(2, 3)]
顶点度数=
[1, 3, 3, 3, 3, 3, 2, 2]
候选割点=
[0, 5, 2, 3]
割点
[5, 2, 3]
可视化图中割边(红色)和割点(红色节点)的效果图
压缩图的可视化效果

结论:

图(graph),是表达对象关系的有效方法;
而针对复杂图的分析,由于结构多变,故用程序逻辑法求解的话,难以编程。
通过使用矩阵计算方法,获取图中的相关信息,对于图分析可起到简捷、高效的作用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/167524.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux关于 gdb 调试器的使用

坚持看完,结尾有思维导图总结 这里写目录标题debug 和 release 版本gdb 常见命令断点逐行调试和观察变量总结debug 和 release 版本 首先要说的是 ,在 Linux 中 gcc 直接编译是不能进行调试的 而是要在加上 -g 选项才能得到可调试的文件 以下程序用一个…

算法第十二期——BFS-双向广搜

双向广搜 应用场景:有确定的起点s和终点t;把从起点到终点的单向搜索,变换为分别从起点出发和从终点出发的“相遇”问题。操作:从起点s(正向搜索)和终点t(逆向搜索)同时开始搜索,当两个搜索产生…

Spring入门-Spring事务管理

文章目录1,Spring事务管理1.1 Spring事务简介1.1.1 相关概念介绍1.1.2 转账案例-需求分析1.1.3 转账案例-环境搭建步骤1:准备数据库表步骤2:创建项目导入jar包步骤3:根据表创建模型类步骤4:创建Dao接口步骤5:创建Service接口和实现类步骤6:添加jdbc.properties文件步…

数据治理与档案信息资源体系建设

如果要评选大数据或者数字化转型领域中哪个词最让人费解、最讲不清楚,“数据治理(Data Governance)”绝对是候选之一。说实话,笔者到现在也没有完全整明白,因为数据治理包含的范围太广了,可以说是包罗万象&…

高潜人才的自我要求

前言,上次写了个《潜力出众的你有这样的特质吗?》,地址如下:点我查看,这次在写个高潜人才的自我要求。本次以6个纬度来进行分析;3是基本要求,4是追求卓越,看你目前做到了哪个级别&am…

跨平台API对接(Python)的使用

Jenkins 是一个开源的、提供友好操作界面的持续集成(CI)工具,起源于 Hudson(Hudson 是商用的),主要用于持续、自动的构建/测试软件项目、监控外部任务的运行。后端可以利用 Jenkins 对任务进行调度运行:后端可利用 HTT…

【进阶】Spring更简单的读取和存储对象

努力经营当下,直至未来明朗! 文章目录一、存储Bean对象一)前置工作:配置扫描路径(重要)二)添加注解存储Bean对象3. 五大类注解:4. 方法注解:6. 相关问题7. 补充【结论、查…

ROS2机器人编程简述humble-第二章-DEVELOPING THE FIRST NODE .2

0.1ROS2机器人编程简述新书推荐-A Concise Introduction to Robot Programming with ROS21.1ROS2机器人编程简述humble-第一章-Introduction2.1ROS2机器人编程简述humble-第二章-First Steps with ROS2 .12.2主要内容是全手工创建一个最简单的自定义节点,其实没啥具…

IB学生必看的时间表(二)

上期谈到在IB预科课程的第一个学年下学期,便要开始作报读大学的准备,到底为什么? 暑假不容松懈 现在来到放暑假了。虽说不用上课,学生没有了学习压力,但就以下三方面来看,学生还是要继续投放心力。 首先&am…

Unity 之 Addressable可寻址系统 -- 代码加载介绍 -- 进阶(一)

Unity 之 可寻址系统 -- 代码加载介绍 -- 进阶(一)一,可寻址系统代码加载1.1 回调形式1.2 异步等待1.3 面板赋值1.4 同步加载二,可寻址系统分标签加载2.1 场景搭建2.2 代码示例2.3 效果展示三,代码加载可寻址的解释概述…

Cadence OrCAD: 跨页符和电源符号命名优先级的一个小问题

Cadence OrCAD: 跨页符和电源符号命名优先级的一个小问题 遇到的问题 最近项目中,有个电源需要做负载端的反馈,类似下图的signal1和signal1N,反馈使用类似伪差分线,把电压信号和负载端的GND都连到DC-DC控制器。DC-DC对应的反馈引…

字节跳动青训营--前端day1

文章目录前言一、 前端1 前端的技术栈2. 前端的边界3. 前端的关注点二、 HTML1. HTML常用标签及语义化2. HTML 语法3. 谁在使用我们写的HTML前言 仅以此文章记录学习历程 一、 前端 解决GUI人机交互问题 1 前端的技术栈 2. 前端的边界 nodejs–服务器端应用 electron… --客…

【数据结构】6.1 图的基本概念和术语

文章目录前言6.1 图的定义和术语前言 图是一种比线性表和树更为复杂的数据结构。 在线性结构中,结点之间的关系属于一个对一个;数据元素之间有着线性关系,每个数据元素只有一个直接前趋和一个直接后继, 在树形结构中,…

算法设计与分析课程

算法的由来 算法的定义 算法的定义:给定计算问题,算法是一系列良定义的计算步骤,逐一执行计算步骤可得到预期的输出。 良定义:定义明确无歧义 计算步骤:计算机可以实现的指令 有了良定义的计算步骤,计算机就…

Java基础篇01-运算符的使用

01| Java中的数据类型 ) 1. 数值型: 序号类型空间占用说明最小值最大值默认值优缺点对比举例1byte8位有符号整数-128(-2^7)127 (2^7-1)0byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一by…

6、Denoising Diffusion Probabilistic Models(扩散模型)

简介 主页:https://hojonathanho.github.io/diffusion/ 扩散模型 (diffusion models)是深度生成模型中新的SOTA。 扩散模型在图片生成任务中超越了原SOTA:GAN,并且在诸多应用领域都有出色的表现,如计算机…

【docker概念和实践 1】 基本概念和组成原理

一、说明 初学Docker就一个字:乱!这是因为Docker是一个庞大体系,初学时不了解全貌,处于“盲人摸象”状态,因不能通晓要领,学了一点,过后就忘了。而了解Docker全貌并非易事,官方文档也…

前端学习记录-Javascript

pink JS基础语法JavaScript核心教程阮一峰JS基础 JS基础语法 初识JS JS三种书写位置:行内、内嵌、引入式。单行注释 ctrl/ 多行注释 shift alt a输入输出语句 声明变量 var age;变量命名规范:字母、数字、下划线、美元符号组成,区分大小写…

质量体系搭建

测试团队的发展历程 初期阶段 特点:提供“保姆式”服务,以发现BUG为主要任务。 工作主要:以功能测试、兼容行测试为主的手工测试,每天进行大量的、重复性的工作,即便如此依然会有遗漏。刚起步的测试团队基本处于这个阶…

LeetCode分类刷题----哈希表篇

哈希表哈希表1.有效的字母异位词242.有效的字母异位词383.赎金信49.字母异位词分组438.找到字符串中所有字母异位词2.两个数组的交集349.两个数组的交集350.两个数组的交集||3.快乐数202202.快乐数4.两数之和1.两数之和5.四数相加454.四数相加||6.三数之和15.三数之和7.四数之和…