图及其应用-程序实现城市交通咨询模拟系统
交通路线图示例数据
假定根据城市道路抽象为如下图,起始地为V1顶点,目的地为V9顶点,对用弧上的距离和此时间段平均速度等信息如下表所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xwRNilvJ-1720750382264)(https://i-blog.csdnimg.cn/direct/347497eb17884334b91cd9071b7bf489.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EgYrkNZG-1720750382264)(https://i-blog.csdnimg.cn/direct/470de54722c9417e84ec232816a07502.png)]
图论知识:
- 图的表示: 使用邻接表来表示图的结构,每个节点都存储了其相邻节点的信息,包括节点名称、距离和速度。
- 最短路径算法: 使用 Dijkstra 算法来计算两个节点之间的最短路径,根据用户选择的标准(距离或时间)来计算最优路径。
编程知识:
- 数据结构: 使用 Python 的字典(dict)来实现图的邻接表表示。
- 算法实现: 使用 Python 的 heapq 模块来实现 Dijkstra 算法中的优先队列。
- 图形用户界面: 使用 Tkinter 库来创建图形用户界面,包括各种控件如输入框、按钮、下拉列表等。
- 事件处理: 通过绑定按钮的 command 属性来处理用户的输入和触发相应的功能,如添加边和查找最优路径。
- 数据存取: 通过读取用户输入的起始节点、目标节点、距离和速度等信息来构建图的结构。
- 结果显示: 将计算得到的最优路径信息显示在 Tkinter 的 Text 控件中。
代码
import tkinter as tk
from tkinter import ttk, messagebox
import heapq
class Graph:
def __init__(self):
self.nodes = {}
def add_edge(self, from_node, to_node, distance, speed):
if from_node not in self.nodes:
self.nodes[from_node] = []
if to_node not in self.nodes:
self.nodes[to_node] = []
self.nodes[from_node].append((to_node, distance, speed))
self.nodes[to_node].append((from_node, distance, speed))
def dijkstra(self, start, goal, criterion='distance'):
queue = [(0, start, [])]
seen = set()
while queue:
(cost, node, path) = heapq.heappop(queue)
if node in seen:
continue
path = path + [node]
seen.add(node)
if node == goal:
return (cost, path)
for (next_node, distance, speed) in self.nodes[node]:
if criterion == 'distance':
total_cost = cost + distance
elif criterion == 'time':
total_cost = cost + (distance / speed)
heapq.heappush(queue, (total_cost, next_node, path))
return float("inf"), []
class App:
def __init__(self, root):
self.root = root
self.root.title("城市交通咨询模拟系统")
self.graph = Graph()
self.create_widgets()
def create_widgets(self):
self.frame = ttk.Frame(self.root, padding="10")
self.frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
ttk.Label(self.frame, text="起始地").grid(row=0, column=0, padx=5, pady=5)
self.start_entry = ttk.Entry(self.frame)
self.start_entry.grid(row=0, column=1, padx=5, pady=5)
ttk.Label(self.frame, text="目的地").grid(row=1, column=0, padx=5, pady=5)
self.end_entry = ttk.Entry(self.frame)
self.end_entry.grid(row=1, column=1, padx=5, pady=5)
ttk.Label(self.frame, text="长度").grid(row=2, column=0, padx=5, pady=5)
self.distance_entry = ttk.Entry(self.frame)
self.distance_entry.grid(row=2, column=1, padx=5, pady=5)
ttk.Label(self.frame, text="平均速度").grid(row=3, column=0, padx=5, pady=5)
self.speed_entry = ttk.Entry(self.frame)
self.speed_entry.grid(row=3, column=1, padx=5, pady=5)
self.add_btn = ttk.Button(self.frame, text="添加路线", command=self.add_edge)
self.add_btn.grid(row=4, column=0, columnspan=2, padx=5, pady=5)
ttk.Label(self.frame, text="选择起始地").grid(row=5, column=0, padx=5, pady=5)
self.src_entry = ttk.Entry(self.frame)
self.src_entry.grid(row=5, column=1, padx=5, pady=5)
ttk.Label(self.frame, text="选择目的地").grid(row=6, column=0, padx=5, pady=5)
self.dest_entry = ttk.Entry(self.frame)
self.dest_entry.grid(row=6, column=1, padx=5, pady=5)
ttk.Label(self.frame, text="决策类型").grid(row=7, column=0, padx=5, pady=5)
self.criterion = ttk.Combobox(self.frame, values=["distance", "time"])
self.criterion.grid(row=7, column=1, padx=5, pady=5)
self.criterion.current(0)
self.search_btn = ttk.Button(self.frame, text="查询最优路线", command=self.search_route)
self.search_btn.grid(row=8, column=0, columnspan=2, padx=5, pady=5)
self.result_text = tk.Text(self.frame, height=10, width=50)
self.result_text.grid(row=9, column=0, columnspan=2, padx=5, pady=5)
def add_edge(self):
from_node = self.start_entry.get()
to_node = self.end_entry.get()
distance = int(self.distance_entry.get())
speed = int(self.speed_entry.get())
self.graph.add_edge(from_node, to_node, distance, speed)
messagebox.showinfo("成功", f"已添加路线: {from_node} -> {to_node}, 长度: {distance}, 平均速度: {speed}")
self.start_entry.delete(0, tk.END)
self.end_entry.delete(0, tk.END)
self.distance_entry.delete(0, tk.END)
self.speed_entry.delete(0, tk.END)
def search_route(self):
start = self.src_entry.get()
goal = self.dest_entry.get()
criterion = self.criterion.get()
cost, path = self.graph.dijkstra(start, goal, criterion)
if criterion == 'distance':
result = f"最短路程: {cost} 单位\n路径: {' -> '.join(path)}"
elif criterion == 'time':
result = f"最短时间: {cost} 小时\n路径: {' -> '.join(path)}"
self.result_text.delete(1.0, tk.END)
self.result_text.insert(tk.END, result)
if __name__ == "__main__":
root = tk.Tk()
app = App(root)
root.mainloop()
运行效果
运行界面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0ZDr9qK2-1720750382265)(https://i-blog.csdnimg.cn/direct/68dd96a4ab3c44d7a87c8a6e27fd61a5.png)]
依次输入数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-amKBIao4-1720750382266)(https://i-blog.csdnimg.cn/direct/79eb078660b84a46bde8eb7ff3fe35fc.png)]
运行结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e0EgiMTr-1720750382266)(https://i-blog.csdnimg.cn/direct/00d1e3ed973740858286af5f5e0fdf7c.png)]