1. Basic knowledge
Directed graph undirected graph
Take an undirected graph as an example:
Adjacency matrix:
Degree matrix (diagonal matrix):
two. Minimum spanning tree
Application: Looking at the network vertices at the city, while looking at the communication network between cities, the weight of the edge is looking at the cost. According to the minimum spanning tree, the lowest cost communication network between cities can be constructed.
1.kruskal algorithm
2. Prim algorithm (Prim algorithm)
Find the minimum spanning tree between points
Code:
#coding:utf-8
"""
最小生成树
"""
import networkx as nx
import matplotlib.pyplot as plt
import numpy as np
from numpy import random
G = nx.Graph()
# Matrix = np.array(random.randint((5), size=(5, 5)))
# print('==Matrix:', Matrix)
# print(maps)
Matrix = np.array( [[3, 4, 0, 2, 2],
[4, 1, 0, 3, 4],
[0, 0, 0, 4, 4],
[2, 3, 4, 0, 3],
[2, 4, 4, 3, 1]])
#实际在用的时候,只用了下三角矩阵
#构建无向图
for i in range(len(Matrix)):
for j in range(len(Matrix)):
if Matrix[i, j] != 0:
G.add_edge(i, j)
nx.draw_networkx(G)
plt.title("G")
plt.show()
class Graph(object):
def __init__(self, Matrix):
self.Matrix = Matrix
self.nodenum = self.get_nodenum()
self.edgenum = self.get_edgenum()
def get_nodenum(self):
return len(self.Matrix)
def get_edgenum(self):
count = 0
for i in range(self.nodenum): # 获取除去对角的下三角矩阵
for j in range(i):
# print('i,j', i, j)
if self.Matrix[i][j] > 0 and self.Matrix[i][j] < 9999:
count += 1
return count
def kruskal(self):
list = []
if self.nodenum <= 0 or self.edgenum < self.nodenum - 1:
return list
edge_list = []
for i in range(self.nodenum): # 获取除去对角的下三角矩阵
for j in range(i):
if self.Matrix[i][j] < 9999:
edge_list.append([i, j, self.Matrix[i][j]])
print('==排序之前边的集合 edge_list:', edge_list)
edge_list.sort(key=lambda a: a[2]) # 已经排好序的边集合
print('==排序以后边的集合 edge_list:', edge_list)
group = [[i] for i in range(self.nodenum)] # 存储代表元列表
print('存储代表元列表', group)
for edge in edge_list:
for i in range(len(group)):
if edge[0] in group[i]:
m = i#开始节点
if edge[1] in group[i]:
n = i#终止节点
if m != n:# 合并联通分量 进行存储元列表更新
list.append(edge)
print('开始节点m,终止节点n:', m, n)
group[m] = group[m] + group[n]
group[n] = []
print('==更新后的代表元列表:', group)
return list
def prim(self):
list = []
if self.nodenum <= 0 or self.edgenum < self.nodenum - 1:
return list
selected_node = [0]
candidate_node = [i for i in range(1, self.nodenum)]#候选节点
# print('==candidate_node:', candidate_node)
while len(candidate_node) > 0:
begin, end, minweight = 0, 0, 9999
for i in selected_node:
for j in candidate_node:
if self.Matrix[i][j] < minweight:
minweight = self.Matrix[i][j]
begin = i#存储开始节点
end = j#存储终止节点
list.append([begin, end, minweight])
selected_node.append(end)#找到权重最小的边 加入可选节点
candidate_node.remove(end)#候选节点被找到 进行移除
return list
#
#
G = Graph(Matrix)
print('邻接矩阵为\n%s' % G.Matrix)
print('节点数据为%d,边数为%d\n' % (G.nodenum, G.edgenum))
print('------最小生成树kruskal算法------')
print(G.kruskal())
print('------最小生成树prim算法')
print(G.prim())
three. Shortest path:
1. Dijkstra algorithm
The Dijkstra algorithm is used to solve the single-source shortest path problem. The so-called single-source shortest path is to specify a starting point and find the shortest path from this starting point to all other points. The essence is to use each vertex as a starting point in turn to update the process of the shortest path.
Example: Find the shortest path from M to each vertex
First construct the adjacency matrix Adjacent, initial state dist[1~n] = inf, dist[M]=0, vertex update state vst[1~n] = 0
Take point M as the starting point:
dist[M] = 0 vst[M] = 0
dist[W] = inf vst[W] = 0
dist[E] = inf vst[E] = 0
dist[D] = inf vst[D] = 0
dist[X] = inf vst[X] = 0
Find the point that has the smallest value in dist and is not used. It is found that dist[M]=0 is the smallest, and vst[M]=0, which is not used, so M is the new starting point.
Find all the vertices reachable by M , For X, W, E
dist[X]=inf> 0+10, update dist[X]=10
dist[W]=inf> 0+5, update dist[W]=5
dist[E]=inf> 0+8, update dist[E]=8
M has been used, vst[M]=1
dist[M] = 0 vst[M] = 1
dist[W] = 5 vst[W] = 0
dist[E] = 8 vst[E] = 0
dist[D] = inf vst[D] = 0
dist[X] = 10 vst[X] = 0
Traverse each vertex in turn...
Inf = float('inf')
# Dijkstra算法,就是依次让每个顶点作为起点,更新最短路的过程。
Adjacent = [[0, 10, 5, Inf, 8],
[10, 0, 3, 1, Inf],
[5, 3, 0, 9, 2],
[Inf, 1, 9, 0, 6],
[8, Inf, 2, 6, 0]]
Src, Dst, N = 0, 4, 5
def dijstra(adj, src, dst, n):
dist = [Inf] * n # 初始化为inf无穷大
dist[src] = 0 # 起始点到起始点距离为0
vst = [0] * n # 记录已经确定的顶点
prev = [0] * n
while True:
now = -1
for u in range(n): # 找到dist最小且vst=0的点作为起点
if not vst[u] and (now == -1 or dist[u] < dist[now]):
now = u
print('====now:', now)
if now == -1: # now未被更新,即表示所有顶点都被使用过,算法结束
break
for v in range(n): # 遍历当前起点now能到达的所有点
if dist[v] > dist[now] + adj[now][v]: # 如果dist[v]大于dist[now] + adj[now][v] 则更新
dist[v] = dist[now] + adj[now][v]
prev[v] = now
print('==dist:', dist)
# assert 1==0
vst[now] = 1 # 当前起点now已被使用过,vst[now]=1
# print('===dist:', dist)
# print('==prev:', prev)
#
# print('==dist[dst]:', dist[dst])
return dist, prev
dist, prev = dijstra(Adjacent, Src, Dst, N)
print('==dist,prev:', dist, prev)
def construct_path(prev, index, path=[]):
path = path + [prev[index]]
if prev[index] == 0:#终止条件
return path
new_path = construct_path(prev, prev[index], path)
return new_path
# res = construct_path(prev, 4,[4])
# print('==res:', res)
for i in range(len(prev)):
path = construct_path(prev, i, [i])
print('{}节点路径为:{}'.format(i, path))
2. Floyd (Floyd)
In essence, whether the shortest path of any two nodes passes through this node, the idea of dp is used to store the intermediate results.
Example:
#Floyd(弗洛伊德)找最短路径 本质任意两个节点最短路径是否经过此节点
import numpy as np
Inf = float('inf')
DIS = [[0, 3, 8, Inf, -4],
[Inf, 0, Inf, 1, 7],
[Inf, 4, 0, Inf, Inf],
[2, Inf, -5, 0, Inf],
[Inf, Inf, Inf, 6, 0]]
Direction = [[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4]]
V = 5
#k就是是否要经过的节点,i就是开始节点,j就是终止节点
for k in range(V):
for i in range(V):
for j in range(V):
if DIS[i][k] + DIS[k][j] < DIS[i][j]:
DIS[i][j] = DIS[i][k] + DIS[k][j]
Direction[i][j] = Direction[i][k]
print('最终的距离矩阵{}'.format(np.array(DIS)))
print('方向矩阵{}'.format(np.array(Direction)))
def construct_path(Direction, i, j, path=[]):
path = path + [Direction[i][j]]
if Direction[i][j] == j:#终止条件
return path
new_path = construct_path(Direction, Direction[i][j], j, path)
return new_path
#找到路径
for i in range(V):
for j in range(V):
path = construct_path(Direction, i, j, [i])
print('{}--{}节点路径为:{}'.format(i, j, path))
The final distance matrix and direction matrix, where the direction matrix can be used to restore the path from the start node to the end node:
reference:
https://blog.csdn.net/weixin_43093481/article/details/82702176
https://www.bilibili.com/video/BV1q4411M7r9?from=search&seid=4042347737055062965