Conocimientos básicos de teoría de grafos: algoritmo de árbol de expansión mínimo kruskal (Kruskal) y algoritmo Prim (algoritmo Prim); algoritmo de ruta más corta Dijkstra (Dijkstra) y Floyd (Floyd)

1. Conocimientos básicos

 

         Gráfico dirigido gráfico no dirigido

Tome un gráfico no dirigido como ejemplo:

Matriz de adyacencia:

Matriz de grados (matriz diagonal):

dos. Árbol de expansión mínimo

Aplicación: si se observan los vértices de la red en la ciudad, mientras se observa la red de comunicación entre ciudades, el peso del borde está considerando el costo, y la red de comunicación de menor costo entre ciudades se puede construir de acuerdo con el árbol de expansión mínimo.

1.algoritmo kruskal

2. Algoritmo Prim (algoritmo Prim)

Encuentra el árbol de expansión mínimo entre puntos

Código:

#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())



 

Tres. Trayectoria más corta:

1. Algoritmo de Dijkstra

El algoritmo de Dijkstra se utiliza para resolver el problema de la ruta más corta de una sola fuente. La llamada ruta más corta de una sola fuente consiste en especificar un punto de partida y encontrar la ruta más corta desde este punto de partida a todos los demás puntos. La esencia es usar cada vértice como punto de partida a su vez para actualizar el proceso del camino más corto.

Ejemplo: Encuentre el camino más corto desde M a cada vértice

             

Primero construya la matriz de adyacencia Adyacente, estado inicial dist [1 ~ n] = inf, dist [M] = 0, estado de actualización del vértice vst [1 ~ n] = 0

Tome el punto M como punto de partida:

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

Encuentre el punto con el valor más pequeño en dist y no usado. Se encuentra que dist [M] = 0 es el más pequeño y vst [M] = 0, que no se usa, entonces M es el nuevo punto de partida.
Encuentre todos los vértices alcanzables por M, para X, W, E
dist [X] = inf> 0 + 10, actualizar dist [X] = 10
dist [W] = inf> 0 + 5, actualizar dist [W] = 5
dist [E ] = inf> 0 + 8,
se ha utilizado la actualización dist [E] = 8 M, 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

Atraviesa cada vértice a su vez ... 

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)

En esencia, si la ruta más corta de dos nodos pasa a través de este nodo, la idea de dp se utiliza para almacenar los resultados intermedios.

Ejemplo:

#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))

 La matriz de distancia final y la matriz de dirección, donde la matriz de dirección se puede utilizar para restaurar la ruta desde el nodo inicial hasta el nodo final:

referencia:

https://blog.csdn.net/weixin_43093481/article/details/82702176

https://www.bilibili.com/video/BV1q4411M7r9?from=search&seid=4042347737055062965

Supongo que te gusta

Origin blog.csdn.net/fanzonghao/article/details/107556540
Recomendado
Clasificación