含负权回路的最短路问题

请问各位,对于含负权回路无向图,最短路问题如何用python解决?(希望有具体的代码)

存在负权回路的图是不能求两点间最短路的,因为在负权回路上不断兜圈子所得的最短路长度可以无限小。
除非把题目改成:求连接两点间权重最小的路(每个点不重复经过)

实现代码:paths_result 包含2点之间(a, c为例)的所有路径 及权值和,比较大小取最小的 -3 即可

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Description: todo
Author: gnn
Date: 2022/12/12
"""

# 如何运用深度遍历算法,输入始发点,目的点,最大步长,得出俩点间的所有路径?
# 例:输入始发点A,目的点F,步长4,得出路径A-B-F、A-C-F、A-E-K-F
# 输入始发点A,目的点F,步长3,得出路径A-B-F、A-C-F
# 输入始发点A,目的点C,步长任意,得出路径A-C
# 定义字典,表示该节点与其他节点的连通关系
from itertools import groupby


def findAllPath(graph, start, end, path=[]):
    # path.append(start)
    path = path + [start]
    if start == end:
        return path

    for node in graph[start]:
        if node not in path:
            newpaths = findAllPath(graph, node, end, path)
            for newpath in newpaths:
                if newpath == end:
                    path.append(newpath)
                    paths.append(path)
    return paths


def get_graph(graph_dict):
    # 打散, 获取相关的两个点
    t = [(kvs[0], v) for kvs in graph_dict.items() for vs in kvs[1] for v in vs]
    # 反转两个点, 获取2个点的相互关系
    t_re = [(t2[1], t2[0]) for t2 in t]
    t.extend(t_re)

    # 聚合得到每个点的下个点
    t_g = groupby(sorted(t, key=lambda x: x[0]), key=lambda x: x[0])
    # 每个点的所有直接连接点
    t_dict = {k: [v[1] for v in list(vs)] for k, vs in t_g}
    return t_dict


if __name__ == '__main__':
    # 图 连接点
    graph = {
        'a': ['b', 'c', 'd'],
        'b': ['c', 'd'],
        'c': ['d', 'e'],
        'd': ['e'],
        'e': ['b', 'd']
    }
    # 权 以 a 到 c 为例, 其他点需要补充
    quan = {
        'a-b': -5,
        'b-c': 2,
        'a-c': 9
    }
    t_dict = get_graph(graph)

    start, end = 'a', 'c'
    paths = []  # 存储所有路径
    findAllPath(t_dict, start, end)
    paths_result=[]
    for vs in paths:
        len_sum = 0
        for i, v in enumerate(vs):
            if i < len(vs)-1:
                len_sum += quan.get(f'{vs[i]}-{vs[i+1]}')
        paths_result.append(["-".join(vs), len_sum])
    print(f'start: {start}, end: {end}, result: {paths_result}')

运行结果:


start: a, end: c, result: [['a-b-c', -3], ['a-c', 9]]

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

/*
 * 求解无向图的单源最短路径
 */
public class NonDirectedGraph {
    private class Vertex{
        private String vertexLabel;//顶点标识
        private List<Edge> adjEdges;//与该顶点邻接的边(点)
        private int dist;//顶点距离(该顶点到起始顶点的距离)
        private Vertex preNode;
        
        public Vertex(String vertexLabel) {
            this.vertexLabel = vertexLabel;
            adjEdges = new LinkedList<>();
            dist = Integer.MAX_VALUE;
            preNode = null;
        }
    }
    private class Edge{
        private Vertex endVertex;
        public Edge(Vertex endVertex) {
            this.endVertex = endVertex;
        }
    }
    
    private Map<String, Vertex> nonDirectedGraph;//保存了图中所有的顶点,边的关系以List形式保存在Vertex类中
    private Vertex startVertex;//图的起始顶点
    
    public NonDirectedGraph(String graphContent) {
        nonDirectedGraph = new LinkedHashMap<>();
        buildGraph(graphContent);
    }
    
    private void buildGraph(String graphContent){
        String[] lines = graphContent.split("\n");
        
        String startNodeLabel, endNodeLabel;
        Vertex startNode, endNode;
        for(int i = 0; i < lines.length; i++){
            String[] nodesInfo = lines[i].split(",");
            startNodeLabel = nodesInfo[1];
            endNodeLabel = nodesInfo[2];
            
            endNode = nonDirectedGraph.get(endNodeLabel);
            if(endNode == null){
                endNode = new Vertex(endNodeLabel);
                nonDirectedGraph.put(endNodeLabel, endNode);
            }
            
            startNode = nonDirectedGraph.get(startNodeLabel);
            if(startNode == null){
                startNode = new Vertex(startNodeLabel);
                nonDirectedGraph.put(startNodeLabel, startNode);
            }
            Edge e = new Edge(endNode);
            //对于无向图而言,起点和终点都要添加边
            endNode.adjEdges.add(e);
            startNode.adjEdges.add(e);
        }
        startVertex = nonDirectedGraph.get(lines[0].split(",")[1]);//总是以文件中第一行第二列的那个标识顶点作为源点
    }
    
    public void unweightedShortestPath(){
        unweightedShortestPath(startVertex);
    }
    
    
    /*
     * 计算源点s到无向图中各个顶点的最短路径
     * 需要一个队列来保存图中的顶点,初始时,源点入队列,然后以广度的形式向外扩散求解其他顶点的最短路径
     */
    private void unweightedShortestPath(Vertex s){
        //初始化
        Queue<Vertex> queue = new LinkedList<>();
        s.dist = 0;
        queue.offer(s);//将源点dist设置为0并入队列
        
        while(!queue.isEmpty()){
            Vertex v = queue.poll();
            for (Edge e : v.adjEdges) {//扫描v的邻接边(点)
                if(e.endVertex.dist == Integer.MAX_VALUE){//如果这个顶点(e.endVertex)未被访问(每个顶点只会入队列一次)
                    e.endVertex.dist = v.dist + 1;//更新该顶点到源点的距离
                    queue.offer(e.endVertex);
                    e.endVertex.preNode = v;//设置该顶点的前驱顶点
                }//end if
            }//end for
        }//end while
    }
    
    //打印图中所有顶点到源点的距离及路径
    public void showDistance(){
        Collection<Vertex> vertexs = nonDirectedGraph.values();
        for (Vertex vertex : vertexs) {
            System.out.print(vertex.vertexLabel + "<--");
            Vertex tmpPreNode = vertex.preNode;
            while(tmpPreNode != null){
                System.out.print(tmpPreNode.vertexLabel + "<--");
                tmpPreNode = tmpPreNode.preNode;
            }
            System.out.println("distance=" + vertex.dist);
        }
    }
}

带负权回路无向图,就需要规定各个点经过的次数,否则就无法求最小值