Basic knowledge of graph theory-minimum spanning tree algorithm kruskal (Kruskal) and Prim algorithm (Prim algorithm); shortest path algorithm Dijkstra (Dijkstra) and Floyd (Floyd)

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

Guess you like

Origin blog.csdn.net/fanzonghao/article/details/107556540