Conhecimento básico da teoria dos grafos - algoritmo de árvore geradora mínima kruskal (Kruskal) e algoritmo Prim (algoritmo Prim); algoritmo de caminho mais curto Dijkstra (Dijkstra) e Floyd (Floyd)

1. Conhecimento básico

 

         Gráfico direcionado gráfico não direcionado

Pegue um gráfico não direcionado como exemplo:

Matriz de adjacência:

Matriz de graus (matriz diagonal):

dois. Árvore de abrangência mínima

Aplicação: Olhando para os vértices da rede na cidade, enquanto olha para a rede de comunicação entre as cidades, o peso da borda está olhando para o custo, e a rede de comunicação de menor custo entre as cidades pode ser construída de acordo com a árvore geradora mínima.

1. algoritmo de cruskal

2. Algoritmo Prim (algoritmo Prim)

Encontre a árvore de abrangência mínima entre os pontos

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



 

três. Caminho mais curto:

1 Algoritmo Dijkstra

O algoritmo Dijkstra é usado para resolver o problema do caminho mais curto de fonte única.O chamado caminho mais curto de fonte única é para especificar um ponto de partida e encontrar o caminho mais curto deste ponto de partida para todos os outros pontos. A essência é usar cada vértice como ponto de partida para atualizar o processo do caminho mais curto.

Exemplo: Encontre o caminho mais curto de M para cada vértice

             

Primeiro construa a matriz de adjacência Adjacente, estado inicial dist [1 ~ n] = inf, dist [M] = 0, estado de atualização do vértice vst [1 ~ n] = 0

Considere o ponto M como ponto 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

Encontre o ponto com o menor valor em dist e não usado. Verifica-se que dist [M] = 0 é o menor e vst [M] = 0, que não é usado, então M é o novo ponto de partida.
Encontre todos os vértices alcançáveis ​​por M, Para X, W, E
dist [X] = inf> 0 + 10, atualizar dist [X] = 10
dist [W] = inf> 0 + 5, atualizar dist [W] = 5
dist [E ] = inf> 0 + 8, atualização dist [E] = 8
M foi usado, 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

Atravesse cada vértice por 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)

Em essência, se o caminho mais curto de quaisquer dois nós passa por esse nó, a ideia de dp é usada para armazenar os resultados intermediários.

Exemplo:

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

 A matriz de distância final e a matriz de direção, onde a matriz de direção pode ser usada para restaurar o caminho do nó inicial ao nó final:

referência:

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

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

Acho que você gosta

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