python: Dijkstra Algorithms

 

# encoding: utf-8 
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : PyCharm 2024.3.6 python 3.11
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/7/7 23:36 
# User      :  geovindu
# Product   : PyCharm
# Project   : Pysimple
# File      : Dijkstra demo.py

import heapq
import networkx as nx
import matplotlib.pyplot as plt

# Dijkstra 通用算法
def dijkstra(graph, start, end):
    dist = {city: float("inf") for city in graph}
    dist[start] = 0
    prev = {city: None for city in graph}
    heap = [(0, start)]
    visited = set()

    while heap:
        current_dist, curr_city = heapq.heappop(heap)
        if curr_city in visited:
            continue
        if curr_city == end:
            break
        visited.add(curr_city)

        for neighbor, weight in graph[curr_city].items():
            if neighbor in visited:
                continue
            new_dist = current_dist + weight
            if new_dist < dist[neighbor]:
                dist[neighbor] = new_dist
                prev[neighbor] = curr_city
                heapq.heappush(heap, (new_dist, neighbor))

    # 回溯路径
    path = []
    temp = end
    while temp is not None:
        path.append(temp)
        temp = prev[temp]
    path.reverse()
    return dist[end], path

# 路网数据:里程(km)、耗时(h)、高速费(元)
graph_km = {
    "深圳": {"惠州":75, "广州":140, "东莞":65},
    "惠州": {"深圳":75, "河源":90},
    "东莞": {"深圳":65, "广州":50},
    "广州": {"深圳":140, "东莞":50, "韶关":190, "佛山":25},
    "佛山": {"广州":25, "肇庆":70},
    "肇庆": {"佛山":70, "梧州":210},
    "梧州": {"肇庆":210, "桂林":260},
    "桂林": {"梧州":260, "柳州":170},
    "柳州": {"桂林":170, "南宁":220},
    "南宁": {"柳州":220},
    "韶关": {"广州":190, "赣州":230},
    "河源": {"惠州":90, "赣州":180},
    "赣州": {"河源":180, "韶关":230, "吉安":240, "南昌":390},
    "吉安": {"赣州":240, "南昌":215, "萍乡":280},
    "南昌": {"赣州":390, "吉安":215, "九江":130, "福州":380},
    "萍乡": {"吉安":280, "长沙":150},
    "长沙": {"萍乡":150, "武汉":280, "株洲":60},
    "株洲": {"长沙":60, "衡阳":130},
    "衡阳": {"株洲":130, "郴州":180},
    "郴州": {"衡阳":180, "韶关":150},
    "九江": {"南昌":130, "武汉":200},
    "武汉": {"九江":200, "长沙":280, "郑州":470},
    "郑州": {"武汉":470, "西安":450},
    "西安": {"郑州":450},
    "福州": {"南昌":380, "厦门":230},
    "厦门": {"福州":230}
}

graph_hour = {
    "深圳": {"惠州":1.0, "广州":1.8, "东莞":0.8},
    "惠州": {"深圳":1.0, "河源":1.3},
    "东莞": {"深圳":0.8, "广州":0.7},
    "广州": {"深圳":1.8, "东莞":0.7, "韶关":2.2, "佛山":0.4},
    "佛山": {"广州":0.4, "肇庆":0.9},
    "肇庆": {"佛山":0.9, "梧州":2.5},
    "梧州": {"肇庆":2.5, "桂林":3.0},
    "桂林": {"梧州":3.0, "柳州":2.0},
    "柳州": {"桂林":2.0, "南宁":2.5},
    "南宁": {"柳州":2.5},
    "韶关": {"广州":2.2, "赣州":2.7},
    "河源": {"惠州":1.3, "赣州":2.0},
    "赣州": {"河源":2.0, "韶关":2.7, "吉安":2.6, "南昌":4.2},
    "吉安": {"赣州":2.6, "南昌":2.3, "萍乡":3.0},
    "南昌": {"赣州":4.2, "吉安":2.3, "九江":1.4, "福州":4.0},
    "萍乡": {"吉安":3.0, "长沙":1.6},
    "长沙": {"萍乡":1.6, "武汉":3.0, "株洲":0.8},
    "株洲": {"长沙":0.8, "衡阳":1.4},
    "衡阳": {"株洲":1.4, "郴州":2.0},
    "郴州": {"衡阳":2.0, "韶关":1.7},
    "九江": {"南昌":1.4, "武汉":2.1},
    "武汉": {"九江":2.1, "长沙":3.0, "郑州":4.8},
    "郑州": {"武汉":4.8, "西安":4.3},
    "西安": {"郑州":4.3},
    "福州": {"南昌":4.0, "厦门":2.4},
    "厦门": {"福州":2.4}
}

graph_cost = {
    "深圳": {"惠州":35, "广州":65, "东莞":30},
    "惠州": {"深圳":35, "河源":42},
    "东莞": {"深圳":30, "广州":25},
    "广州": {"深圳":65, "东莞":25, "韶关":85, "佛山":15},
    "佛山": {"广州":15, "肇庆":35},
    "肇庆": {"佛山":35, "梧州":100},
    "梧州": {"肇庆":100, "桂林":120},
    "桂林": {"梧州":120, "柳州":70},
    "柳州": {"桂林":70, "南宁":95},
    "南宁": {"柳州":95},
    "韶关": {"广州":85, "赣州":105},
    "河源": {"惠州":42, "赣州":80},
    "赣州": {"河源":80, "韶关":105, "吉安":110, "南昌":180},
    "吉安": {"赣州":110, "南昌":95, "萍乡":125},
    "南昌": {"赣州":180, "吉安":95, "九江":55, "福州":170},
    "萍乡": {"吉安":125, "长沙":65},
    "长沙": {"萍乡":65, "武汉":130, "株洲":25},
    "株洲": {"长沙":25, "衡阳":55},
    "衡阳": {"株洲":55, "郴州":80},
    "郴州": {"衡阳":80, "韶关":65},
    "九江": {"南昌":55, "武汉":85},
    "武汉": {"九江":85, "长沙":130, "郑州":210},
    "郑州": {"武汉":210, "西安":190},
    "西安": {"郑州":190},
    "福州": {"南昌":170, "厦门":105},
    "厦门": {"福州":105}
}

# 城市坐标布局
city_pos = {
    "深圳":(5,0), "惠州":(6,1), "东莞":(4,0), "广州":(3,0),
    "佛山":(2,0), "肇庆":(1,1), "梧州":(-2,2), "桂林":(-3,4),
    "柳州":(-4,3), "南宁":(-5,1), "韶关":(2,4), "河源":(7,3),
    "赣州":(8,6), "吉安":(9,9), "南昌":(10,8), "萍乡":(7,8),
    "长沙":(6,9), "株洲":(6,8), "衡阳":(6,6), "郴州":(6,4),
    "九江":(11,9), "武汉":(9,11), "郑州":(10,14), "西安":(7,15),
    "福州":(13,7), "厦门":(14,4)
}
all_city_list = list(city_pos.keys())

def draw_route(start, end, path_km, total_km):
    G = nx.Graph()
    for city, neighbors in graph_km.items():
        for neighbor, km in neighbors.items():
            G.add_edge(city, neighbor, weight=km)
    plt.figure(figsize=(14,11))
    # 全部节点、普通道路
    nx.draw_networkx_nodes(G, city_pos, node_color="#cfe2f3", node_size=1200)
    nx.draw_networkx_edges(G, city_pos, edge_color="#cccccc", width=1)
    nx.draw_networkx_labels(G, city_pos, font_size=9, font_weight="bold")
    # 最优路径红色加粗
    path_edges = list(zip(path_km, path_km[1:]))
    nx.draw_networkx_edges(G, city_pos, edgelist=path_edges, edge_color="red", width=5)
    # 起点终点特殊标记
    nx.draw_networkx_nodes(G, city_pos, nodelist=[start], node_color="#ff7777", node_size=1500)
    nx.draw_networkx_nodes(G, city_pos, nodelist=[end], node_color="#77ff77", node_size=1500)
    # 全部英文标题,无中文,彻底消除警告
    plt.title(f"{start} to {end} Shortest Distance Route | Total: {total_km} km\nPath: {' -> '.join(path_km)}", fontsize=14)
    plt.axis("off")
    plt.tight_layout()
    plt.show()

if __name__ == "__main__":
    # Windows专用中文字体配置,微软雅黑系统自带,不会缺失
    plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"]
    plt.rcParams["axes.unicode_minus"] = False
    print("===== China City Highway Route Planner =====")
    print("Available cities:")
    print(", ".join(all_city_list))
    print("-" * 60)

    # 交互输入
    while True:
        start_input = input("Input start city: ").strip()
        end_input = input("Input destination city: ").strip()
        # 校验城市是否存在
        if start_input not in all_city_list or end_input not in all_city_list:
            print("City not found, please re-enter!\n")
            continue
        if start_input == end_input:
            print("Start and destination cannot be the same!\n")
            continue
        break

    # 计算三种方案
    km_total, km_path = dijkstra(graph_km, start_input, end_input)
    hour_total, hour_path = dijkstra(graph_hour, start_input, end_input)
    cost_total, cost_path = dijkstra(graph_cost, start_input, end_input)

    # 控制台输出结果(英文)
    print("\n" + "="*60)
    print(f"【{start_input} -> {end_input} Three Optimal Plans】")
    print("="*60)
    print(f"📏 Shortest Distance: Total {km_total} km")
    print(f"    Route: {' -> '.join(km_path)}")
    print(f"\n⏰ Shortest Time: Total {hour_total:.1f} hours")
    print(f"    Route: {' -> '.join(hour_path)}")
    print(f"\n💰 Minimum Toll Fee: Total {cost_total} RMB")
    print(f"    Route: {' -> '.join(cost_path)}")
    print("="*60)

    # 绘制路网图
    draw_route(start_input, end_input, km_path, km_total)

  

posted @ 2026-07-07 23:46  ®Geovin Du Dream Park™  阅读(9)  评论(0)    收藏  举报