diff --git a/EDGE.py b/EDGE.py new file mode 100644 index 0000000..4ee05d7 --- /dev/null +++ b/EDGE.py @@ -0,0 +1,487 @@ +# -*- encoding: utf-8 -*- +from head import * +from NODE import * + +N = Node() + + + + + + + + + + + + + +class Edge: + def __init__(self): + self.mark = [] + # 记录已标记的节点数目(连接操作) + self.user_cur = 0 + # 记录用户所在点 + + def node_edge(self, no, n1, n2): # 根据节点返回编号 + if n1 > n2: + n = n1 + n1 = n2 + n2 = n + for e in d.Edges: + if e[1] == n1 and e[2] == n2 and e[8] == no: + return e[0] + return -1 + + def edge_mark_display(self): + + for w in frame_right.winfo_children(): + w.destroy() + # 清除右侧组件 + cura = "无" + cur1 = -1 + curb = "无" + cur2 = -1 + lab = tk.Label(frame_right, text="连接操作", bg=RED, fg=BLACK, font=('微软雅黑', 20)) + lab.place(relx=0.18, rely=0.02, width=200, height=30) + for i in d.Nodes: + if i[2] == 1: + cura = str(i[1]) + cur1 = i[0] + if i[2] == 2: + curb = str(i[1]) + cur2 = i[0] + E = 0 + for e in d.Edges: + + if ((cur1 == e[1] and cur2 == e[2]) or (cur2 == e[1] and cur1 == e[2])): + if e[8] == 1 and e[3] == 1 and E < 1: + E = 1 + elif e[8] == 2 and e[3] == 1 and E < 2: + E = 2 + elif e[8] == 3 and e[3] == 1 and E < 3: + E = 3 + y0 = 0.1 + B = tk.Button(frame_right, text="建立为完全图", command=lambda: self.edge_addall()) + B.place(relx=0.15, rely=y0 - 0.02, width=80, height=30) + B = tk.Button(frame_right, text="删除所有链接", command=lambda: self.edge_delall()) + B.place(relx=0.65, rely=y0 - 0.02, width=80, height=30) + # 当前两个节点信息 + + laba1 = tk.Label(frame_right, text="当前节点1:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + laba2 = tk.Label(frame_right, text=f"{cura}", bg=BLUE, fg=BLACK, font=('微软雅黑', 8)) + laba1.place(relx=0.05, rely=0.02 + y0, width=80, height=30) + laba2.place(relx=0.35, rely=0.02 + y0, width=50, height=30) + labb1 = tk.Label(frame_right, text="当前节点2:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + labb2 = tk.Label(frame_right, text=f"{curb}", bg=BLUE, fg=BLACK, font=('微软雅黑', 8)) + labb1.place(relx=0.52, rely=0.02 + y0, width=80, height=30) + labb2.place(relx=0.82, rely=0.02 + y0, width=50, height=30) + # 当前链接信息 + cur = -1 + for edge in d.Edges: + if edge[8] == 1 and edge[3] == 1 and d.Nodes[edge[1]][2] + d.Nodes[edge[2]][2] == 3: + cur = edge[0] + + if E == 0: + text = "两点间不存在链接" + else: + text = "两点间存在" + str(E) + "条链接" + + lab1 = tk.Label(frame_right, text=f"{text}", bg=RED, fg=BLACK, font=('微软雅黑', 15)) + lab1.place(relx=0.05, rely=0.08 + y0, width=200, height=30) + + if E == 0: + B = tk.Button(frame_right, text="建立链接", command=lambda: self.edge_add()) + B.place(relx=0.7, rely=0.08 + y0, width=80, height=30) + elif E == 1: + B = tk.Button(frame_right, text="删除链接", command=lambda: self.edge_del()) + B.place(relx=0.7, rely=0.08 + y0, width=80, height=30) + if not E == 0: + y0 += 0.1 + lab = tk.Label(frame_right, text="链接一", bg=RED, fg=BLACK, font=('微软雅黑', 15)) + lab.place(relx=0.1, rely=0.08 + y0, width=150, height=30) + + lab1 = tk.Label(frame_right, text="当前链接", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + if cur == -1: + text = "无" + else: + text = str(d.Edges[cur][5]) + lab2 = tk.Label(frame_right, text=f"{text}", bg=BLUE, fg=BLACK, font=('微软雅黑', 8)) + B = tk.Button(frame_right, text="设置标签", command=lambda: self.edge_rename()) + lab1.place(relx=0.1, rely=0.13 + y0, width=80, height=30) + lab2.place(relx=0.4, rely=0.13 + y0, width=80, height=30) + B.place(relx=0.7, rely=0.13 + y0, width=80, height=30) + + lab1 = tk.Label(frame_right, text="链接成本", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + if cur == -1: + text = "无" + else: + text = str(d.Edges[cur][6]) + lab2 = tk.Label(frame_right, text=f"{text}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + B = tk.Button(frame_right, text="设置成本", command=lambda: self.edge_recost()) + lab1.place(relx=0.1, rely=0.18 + y0, width=80, height=30) + lab2.place(relx=0.4, rely=0.18 + y0, width=80, height=30) + B.place(relx=0.7, rely=0.18 + y0, width=80, height=30) + + lab1 = tk.Label(frame_right, text="链接时间", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + if cur == -1: + text = "无" + else: + text = str(d.Edges[cur][7]) + lab2 = tk.Label(frame_right, text=f"{text}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + B = tk.Button(frame_right, text="设置时间", command=lambda: self.edge_retime()) + lab1.place(relx=0.1, rely=0.23 + y0, width=80, height=30) + lab2.place(relx=0.4, rely=0.23 + y0, width=80, height=30) + B.place(relx=0.7, rely=0.23 + y0, width=80, height=30) + # print ("cur",cur1,cur2) + + # print (E) + if E == 1: + + B = tk.Button(frame_right, text="增加一条连接", command=lambda: self.newedge_add(2, cur1, cur2)) + B.place(relx=0.1, rely=0.3 + y0, width=150, height=30) + elif E >= 2: + cur = self.node_edge(2, cur1, cur2) + lab = tk.Label(frame_right, text="链接二", bg=RED, fg=BLACK, font=('微软雅黑', 15)) + lab.place(relx=0.1, rely=0.28 + y0, width=150, height=30) + lab1 = tk.Label(frame_right, text="当前链接", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + if cur == -1: + text = "无" + else: + text = str(d.Edges[cur][5]) + lab2 = tk.Label(frame_right, text=f"{text}", bg=BLUE, fg=BLACK, font=('微软雅黑', 8)) + B = tk.Button(frame_right, text="设置标签", command=lambda n=cur: self.newedge_rename(n)) + lab1.place(relx=0.1, rely=0.33 + y0, width=80, height=30) + lab2.place(relx=0.4, rely=0.33 + y0, width=80, height=30) + B.place(relx=0.7, rely=0.33 + y0, width=80, height=30) + + lab1 = tk.Label(frame_right, text="链接成本", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + if cur == -1: + text = "无" + else: + text = str(d.Edges[cur][6]) + lab2 = tk.Label(frame_right, text=f"{text}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + B = tk.Button(frame_right, text="设置成本", command=lambda n=cur: self.newedge_recost(n)) + lab1.place(relx=0.1, rely=0.38 + y0, width=80, height=30) + lab2.place(relx=0.4, rely=0.38 + y0, width=80, height=30) + B.place(relx=0.7, rely=0.38 + y0, width=80, height=30) + + lab1 = tk.Label(frame_right, text="链接时间", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + if cur == -1: + text = "无" + else: + text = str(d.Edges[cur][7]) + lab2 = tk.Label(frame_right, text=f"{text}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + B = tk.Button(frame_right, text="设置时间", command=lambda n=cur: self.newedge_retime(n)) + lab1.place(relx=0.1, rely=0.43 + y0, width=80, height=30) + lab2.place(relx=0.4, rely=0.43 + y0, width=80, height=30) + B.place(relx=0.7, rely=0.43 + y0, width=80, height=30) + if E == 2: + B = tk.Button(frame_right, text="增加一条连接", command=lambda: self.newedge_add(3, cur1, cur2)) + B.place(relx=0.1, rely=0.5 + y0, width=150, height=30) + B = tk.Button(frame_right, text="删除一条连接", command=lambda: self.newedge_del(2, cur1, cur2)) + B.place(relx=0.1, rely=0.55 + y0, width=150, height=30) + B = tk.Button(frame_right, text="删除多余连接", command=lambda: self.newedge_del_all(1)) + B.place(relx=0.1, rely=0.6 + y0, width=150, height=30) + elif E == 3: + cur = self.node_edge(3, cur1, cur2) + y0 += 0.2 + lab = tk.Label(frame_right, text="链接三", bg=RED, fg=BLACK, font=('微软雅黑', 15)) + lab.place(relx=0.1, rely=0.28 + y0, width=150, height=30) + + lab1 = tk.Label(frame_right, text="当前链接", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + if cur == -1: + text = "无" + else: + text = str(d.Edges[cur][5]) + lab2 = tk.Label(frame_right, text=f"{text}", bg=BLUE, fg=BLACK, font=('微软雅黑', 8)) + B = tk.Button(frame_right, text="设置标签", command=lambda n=cur: self.newedge_rename(n)) + lab1.place(relx=0.1, rely=0.33 + y0, width=80, height=30) + lab2.place(relx=0.4, rely=0.33 + y0, width=80, height=30) + B.place(relx=0.7, rely=0.33 + y0, width=80, height=30) + + lab1 = tk.Label(frame_right, text="链接成本", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + if cur == -1: + text = "无" + else: + text = str(d.Edges[cur][6]) + lab2 = tk.Label(frame_right, text=f"{text}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + B = tk.Button(frame_right, text="设置成本", command=lambda n=cur: self.newedge_recost(n)) + lab1.place(relx=0.1, rely=0.38 + y0, width=80, height=30) + lab2.place(relx=0.4, rely=0.38 + y0, width=80, height=30) + B.place(relx=0.7, rely=0.38 + y0, width=80, height=30) + + lab1 = tk.Label(frame_right, text="链接时间", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + if cur == -1: + text = "无" + else: + text = str(d.Edges[cur][7]) + lab2 = tk.Label(frame_right, text=f"{text}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + B = tk.Button(frame_right, text="设置时间", command=lambda n=cur: self.newedge_retime(n)) + lab1.place(relx=0.1, rely=0.43 + y0, width=80, height=30) + lab2.place(relx=0.4, rely=0.43 + y0, width=80, height=30) + B.place(relx=0.7, rely=0.43 + y0, width=80, height=30) + B = tk.Button(frame_right, text="删除一条连接", command=lambda: self.newedge_del(3, cur1, cur2)) + B.place(relx=0.1, rely=0.5 + y0, width=150, height=30) + B = tk.Button(frame_right, text="删除多余连接", command=lambda: self.newedge_del_all(1)) + B.place(relx=0.1, rely=0.55 + y0, width=150, height=30) + + def edge_merge_cost(self, n1, n2): + cur1 = node_edge(n1, n2)# 初始化三条可能的边的编号 + cur2 = node_edge(n1, n2, 2)# 初始化三条可能的边的编号 + cur3 = node_edge(n1, n2, 3)# 初始化三条可能的边的编号 + edges = [(cur1, d.Edges[cur1][6]), (cur2, d.Edges[cur2][6]), (cur3, d.Edges[cur3][6])]#提出编号与路径花费 + valid_edges = [(edge, cost) for edge, cost in edges if d.Edges[edge][3] == 1]# 过滤出存在的边 + valid_edges.sort(key=lambda x: x[1])# 按照 cost 排序,保留 cost 最小的边 + for idx, (edge, _) in enumerate(valid_edges): + d.Edges[edge][8] = idx + 1 # 设置边的优先级 + d.Edges[edge][0] = edge # 确保边的索引正确 + for edge, _ in valid_edges[1:]:# 对于非最优边,设置其为不显示 + d.Edges[edge][3] = 0 + + # def edge_merge_cost(self, n1, n2): + # # 保留cost最小的一条,其他路径都不显示 + # cur1 = G.node_edge(n1, n2) + # cur2 = self.node_edge(2, n1, n2) + # cur3 = self.node_edge(3, n1, n2) + # # print(d.Edges[cur1]) + # # print(d.Edges[cur2]) + # # print(d.Edges[cur3]) + # if d.Edges[cur2][3] == 1 and d.Edges[cur2][6] < d.Edges[cur1][6]: + # e = d.Edges[cur1].copy() + # d.Edges[cur1] = d.Edges[cur2].copy() + # d.Edges[cur2] = e.copy() + # d.Edges[cur1][8] = 1 + # d.Edges[cur2][8] = 2 + # if d.Edges[cur2][3] == 1 and d.Edges[cur3][6] < d.Edges[cur1][6]: + # e = d.Edges[cur1].copy() + # d.Edges[cur1] = d.Edges[cur3].copy() + # d.Edges[cur3] = e.copy() + # d.Edges[cur1][8] = 1 + # d.Edges[cur3][8] = 3 + # if d.Edges[cur2][3] == 1 and d.Edges[cur3][3] == 1 and d.Edges[cur3][6] < d.Edges[cur2][6]: + # e = d.Edges[cur2].copy() + # d.Edges[cur2] = d.Edges[cur3].copy() + # d.Edges[cur3] = e.copy() + # d.Edges[cur2][8] = 2 + # d.Edges[cur3][8] = 3 + # d.Edges[cur2][3] = 0 + # d.Edges[cur3][3] = 0 + # d.Edges[cur1][0] = cur1 + # d.Edges[cur2][0] = cur2 + # d.Edges[cur3][0] = cur3 + + def edge_merge_time(self, n1, n2): + cur1 = node_edge(n1, n2)# 初始化三条可能的边的编号 + cur2 = node_edge(n1, n2, 2)# 初始化三条可能的边的编号 + cur3 = node_edge(n1, n2, 3)# 初始化三条可能的边的编号 + edges = [(cur1, d.Edges[cur1][7]), (cur2, d.Edges[cur2][7]), (cur3, d.Edges[cur3][7])]#提出编号与路径花费 + valid_edges = [(edge, cost) for edge, cost in edges if d.Edges[edge][3] == 1]# 过滤出存在的边 + valid_edges.sort(key=lambda x: x[1])# 按照 cost 排序,保留 cost 最小的边 + for idx, (edge, _) in enumerate(valid_edges): + d.Edges[edge][8] = idx + 1 # 设置边的优先级 + d.Edges[edge][0] = edge # 确保边的索引正确 + for edge, _ in valid_edges[1:]:# 对于非最优边,设置其为不显示 + d.Edges[edge][3] = 0 + + + + def edge_del_all(self, mode): + # mode = 1:优先最短路径 + # mode = 2:优先最短时间 + # cur1 = node_edge() + if mode == 1: + for e in d.Edges: + if (e[8] == 2 and e[3] == 1) or (e[8] == 3 and e[3] == 1): + self.edge_merge_cost(e[1], e[2]) + else: + for e in d.Edges: + if (e[8] == 2 and e[3] == 1) or (e[8] == 3 and e[3] == 1): + self.edge_merge_time(e[1], e[2]) + G.draw() + + def newedge_del_all(self, mode): + self.edge_del_all(mode) + self.edge_mark_display() + + def newedge_recost(self, no): + edge = d.Edges[no] + if not edge: + tk.messagebox.askokcancel(title='错误', message='链接不合法') + result = tkinter.simpledialog.askinteger(title='修改连接花费', prompt='请输入修改后的时间:', + initialvalue=edge[7]) + if result: + edge[6] = result + G.draw() + self.edge_mark_display() + + def newedge_retime(self, no): + edge = d.Edges[no] + if not edge: + tk.messagebox.askokcancel(title='错误', message='链接不合法') + result = tkinter.simpledialog.askinteger(title='修改连接时间', prompt='请输入修改后的时间:', + initialvalue=edge[7]) + if result: + edge[7] = result + G.draw() + self.edge_mark_display() + + def newedge_rename(self, no): + edge = d.Edges[no] + if not edge: + tk.messagebox.askokcancel(title='错误', message='链接不合法') + result = tkinter.simpledialog.askstring(title='修改连接标签', prompt='请输入修改后的标签:', + initialvalue=edge[5]) + if result: + edge[5] = result + G.draw() + self.edge_mark_display() + + def newedge_add(self, no, na, nb): + e = self.node_edge(no, na, nb) + d.Edges[e][3] = 1 + G.draw() + self.edge_mark_display() + + def newedge_del(self, no, na, nb): + e = self.node_edge(no, na, nb) + d.Edges[e][3] = 0 + # print(d.Edges[e]) + G.draw() + self.edge_mark_display() + + def node_mark1(self, name): + if name >= len(d.Nodes): + N.node_404(name) + return + + for node in d.Nodes: + if node[0] == name: + node[2] = 1 + elif node[2] == 1: + node[2] = 0 + G.draw() + self.edge_mark_display() + + def node_mark2(self, name): + if name >= len(d.Nodes): + N.node_404(name) + return + + for node in d.Nodes: + if node[0] == name: + node[2] = 2 + elif node[2] == 2: + node[2] = 0 + G.draw() + self.edge_mark_display() + + + + def edge_add(self): + for edge in d.Edges: + if d.Nodes[edge[1]][2] + d.Nodes[edge[2]][2] == 3: + if edge[8] == 1 and edge[3] == 1: + tk.messagebox.askokcancel(title='错误', message='已存在连线') + return + else: + edge[3] = 1 + G.draw() + self.edge_mark_display() + return + tk.messagebox.askokcancel(title='错误', message='请选择两个节点') + + def edge_del(self): + for edge in d.Edges: + if d.Nodes[edge[1]][2] + d.Nodes[edge[2]][2] == 3: + edge[3] = 0 + G.draw() + self.edge_mark_display() + return + tk.messagebox.askokcancel(title='错误', message='请选择两个节点') + + def edge_delall(self): + for edge in d.Edges: + edge[3] = 0 + G.draw() + self.edge_mark_display() + + def edge_addall(self): + for edge in d.Edges : + if edge[8] == 1: + edge[3] = 1 + G.draw() + self.edge_mark_display() + + def edge_rename(self): + for edge in d.Edges: + if d.Nodes[edge[1]][2] + d.Nodes[edge[2]][2] == 3: + if edge[3] == 0: + tk.messagebox.askokcancel(title='错误', message='不存在连线') + return + else: + result = tkinter.simpledialog.askstring(title='修改连接标签', prompt='请输入修改后的标签:', + initialvalue=edge[5]) + if(result): + edge[5] = result + G.draw() + self.edge_mark_display() + return + tk.messagebox.askokcancel(title='错误', message='请选择两个节点') + + def edge_recost(self): + for edge in d.Edges: + if d.Nodes[edge[1]][2] + d.Nodes[edge[2]][2] == 3: + if edge[3] == 0: + tk.messagebox.askokcancel(title='错误', message='不存在连线') + return + else: + result = tkinter.simpledialog.askinteger(title='修改连接成本', prompt='请输入修改后的成本:', + initialvalue=edge[6]) + if result: + edge[6] = result + G.draw() + self.edge_mark_display() + return + tk.messagebox.askokcancel(title='错误', message='请选择两个节点') + + def edge_retime(self): + for edge in d.Edges: + if d.Nodes[edge[1]][2] + d.Nodes[edge[2]][2] == 3: + if edge[3] == 0: + tk.messagebox.askokcancel(title='错误', message='不存在连线') + return + else: + result = tkinter.simpledialog.askinteger(title='修改连接时间', prompt='请输入修改后的时间:', + initialvalue=edge[7]) + if result: + edge[7] = result + G.draw() + self.edge_mark_display() + return + tk.messagebox.askokcancel(title='错误', message='请选择两个节点') + + def edge_mark(self): + for i in d.Edges: + if d.Nodes[i[1]][2] == True and d.Nodes[i[2]][2] == True: + i[4] = True + + def edge_nmark(self): + for i in d.Edges: + if d.Nodes[i[1]][2] == True and d.Nodes[i[2]][2] == True: + i[4] = False + + def edge_clear(self): + for edge in d.Edges: + edge[4] = False + G.draw() + + + + + +if __name__ == '__main__': + G.draw() + E = Edge() + E.edge_mark_display() + mainloop() \ No newline at end of file diff --git a/NODE.py b/NODE.py new file mode 100644 index 0000000..062767f --- /dev/null +++ b/NODE.py @@ -0,0 +1,230 @@ +# -*- encoding: utf-8 -*- +from head import * + +class Node: + # 标记节点按钮 + def node_mark_display(self): + for w in frame_right.winfo_children(): + w.destroy() + # 清除右侧组件 + curx = -1 + y0 = 0.1 + for i in d.Nodes: + if i[2] == 1: + curx = i[0] + lab = tk.Label(frame_right, text="节点操作", bg=RED, fg=BLACK, font=('微软雅黑', 20)) + lab.place(relx=0.18, rely=0.02, width=200, height=30) + lab1 = tk.Label(frame_right, text=f"当前共有{len(d.Nodes)}个节点", bg=RED, fg=BLACK, font=('微软雅黑', 15)) + lab1.place(relx=0.1, rely=0.0 + y0, width=200, height=30) + lab1 = tk.Label(frame_right, text="当前节点:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + if curx == -1: + text = "未选择" + else: + text = f"{d.Nodes[curx][1]}" + + lab2 = tk.Label(frame_right, text=text, bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.05 + y0, width=80, height=30) + lab2.place(relx=0.4, rely=0.05 + y0, width=80, height=30) + B = tk.Button(frame_right, text="设置标签", command=lambda: self.node_rename()) + B.place(relx=0.7, rely=0.05 + y0, width=80, height=30) + B = tk.Button(frame_right, text="删除当前节点", command=lambda: self.node_del_exact()) + B.place(relx=0.1, rely=0.1 + y0, width=150, height=30) + if d.Nodes[curx][4] == 1: + text = '设为非必经节点' + else: + text = '设为必经节点' + B = tk.Button(frame_right, text=text, command=lambda: self.dominator(curx)) + B.place(relx=0.1, rely=0.15 + y0, width=150, height=30) + B = tk.Button(frame_right, text="增加一个节点", command=lambda: self.node_add()) + B.place(relx=0.1, rely=0.25 + y0, width=150, height=30) + B = tk.Button(frame_right, text="减少一个节点", command=lambda: self.node_del()) + B.place(relx=0.1, rely=0.3 + y0, width=150, height=30) + + def dominator(self, x): + d.Nodes[x][4] ^= 1 + G.draw() + self.node_mark_display() + + def node_mark(self, name): + if name >= len(d.Nodes): + self.node_404(name) + return + + for node in d.Nodes: + if node[0] == name: + node[2] = 1 + else: + node[2] = 0 + G.draw() + self.node_mark_display() + + def node_del_exact(self): + if d.nodes_num <= 2:# 若删除节点以后节点过少,则直接返回并警告 + tk.messagebox.askokcancel(title='错误', message='节点过少') + return + flag = 0 + cur = -1 + for node in d.Nodes:# 寻找当前选定的节点 + if node[2] == 1: + cur = node[0] + flag = 1 + if flag == 0: + tk.messagebox.askokcancel(title='错误', message='未选择节点') + return + if d.source == 1:# 如果是均匀分布,则重新计算点的坐标 + d.nodes_num -= 1#节点数目减一 + d.ang = 360 / d.nodes_num#重新计算圆心角 + nodes = d.Nodes.copy()#复制节点 + d.Nodes.clear()#清除Data中的节点 + num = 0 + for n in nodes:#逐个复制节点 + if n[0] == cur:#若是删除的节点,则不复制 + continue + n[0] = num#重新编号 + rad = math.radians(num * d.ang)#计算当前角度 + x = int(math.cos(rad) * d.R)#计算当前点x坐标(相对) + y = int(math.sin(rad) * d.R)#计算当前点y坐标(相对) + n[3] = (d.center[0] + x, d.center[1] + y)#计算绝对坐标 + d.Nodes.append(n)#将当前点加入点集合中 + num += 1 + edges = d.Edges.copy()#将原有边集复制出来 + d.Edges.clear()#删除Data中的边集 + num = 0 + for e in edges:#复制边 + if e[1] == cur or e[2] == cur:#删除的边不复制 + continue + if e[1] > cur:#修改边对应的点的编号 + e[1] -= 1 + if e[2] > cur:#修改边对应的点的编号 + e[2] -= 1 + e[0] = num#重新编号 + d.Edges.append(e)#将边加入边集中 + num += 1 + # 如果是按照经纬度分布,则重新计算比例尺 + elif d.source == 2: + name = [] + for i in range(len(d.name)): + if not i == cur: + name.append(d.name[i]) + d.name = name.copy() + d.nodes_num -= 1 + + d.coordinate = d.coord_creat() # 纯节点坐标 + d.Nodes = d.JI_nodes_creat() # 节点列表 + d.Edges = d.JI_edges_creat() + d.JI_edge_add(2) + d.JI_edge_add(3) + + elif d.source == 3: + name = [] + for i in range(len(d.name)): + if not i == cur: + name.append(d.name[i]) + d.name = name.copy() + d.nodes_num -= 1 + + d.coordinate = d.coord_creat() # 纯节点坐标 + d.Nodes = d.LIAO_nodes_creat() # 节点列表 + d.Edges = d.LIAO_edges_creat() + d.LIAO_edge_add(2) + d.LIAO_edge_add(3) + + G.draw() + self.node_mark_display() + + def node_rename(self): + flag = 0 + for node in d.Nodes: + if node[2] == 1: + cur = node + flag = 1 + if flag == 1: + result = tkinter.simpledialog.askstring(title='修改节点标签', prompt='请输入修改后的标签:', initialvalue=cur[1]) + else: + tk.messagebox.askokcancel(title='错误', message='未选择节点') + return + for node in d.Nodes: # 检查新的名称是否已经存在 + if node[1] == result: + return "Error: name already exists" + if result: + cur[1] = result + G.draw() + self.node_mark_display() + + def node_clear(self): + for node in d.Nodes: + node[2] = False + G.draw() + + + + def node_add(self): + # 增加一个节点 + nodes = len(d.Nodes) + 1 + # 如果节点数目大于五,则将连接详细信息改为不显示 + if nodes > 5: + d.edgeinfo = 0 + self.node_init(nodes) + G.draw() + self.node_mark_display() + + def node_set(self): + node = tkinter.simpledialog.askinteger(title='修改节点数目', prompt='请输入修改后的节点数目:', + initialvalue=str(len(d.Nodes))) + if node: + self.node_init(node) + G.draw() + + def node_del(self): + if d.nodes_num <= 2: + tk.messagebox.askokcancel(title='错误', message='节点过少') + return + nodes = len(d.Nodes) - 1 + if nodes < 6: + d.edgeinfo = 1 + self.node_init(nodes) + G.draw() + self.node_mark_display() + + def node_init(self, node): + if not node: + return + if d.source == 1: + d.data(node) + elif d.source == 2: + if node > 13: + tk.messagebox.askokcancel(title='错误', message='节点过多') + return + d.HEI_data(node) + else: + if node > 13: + tk.messagebox.askokcancel(title='错误', message='节点过多') + return + d.LIAO_data(node) + if node > 5: + d.edgeinfo = 0 + else: + d.edgeinfo = 1 + + def graph_del(self): + global d + del d + + + + def node_refresh(self): + nodes = len(d.Nodes) + self.node_init(nodes) + G.draw() + self.node_mark_display() + + def node_404(self, name): + # 弹出对话框 + tk.messagebox.askokcancel(title='错误', message='该节点不存在') + # print(result) + +if __name__ == '__main__': + G.draw() + node = Node() + node.node_mark_display() + mainloop() \ No newline at end of file diff --git a/SOLVE.py b/SOLVE.py new file mode 100644 index 0000000..46386d5 --- /dev/null +++ b/SOLVE.py @@ -0,0 +1,878 @@ +# -*- encoding: utf-8 -*- +from head import * +from NODE import * +from EDGE import * +N = Node() +E = Edge() + +class Solve: + def __init__(self): + self.ans = [] # 记录答案 + self.mutians = [] # 若有多个最短路,则保存在mutians中 + self.way_sum = 0 # 记录遍历的路径数目 + self.minn = float("inf")#初始化最小值为正无穷 + self.start = 0 # 起始点 + self.end = 0 # 终点 + self.mark = [] # 记录该点是否已经经过 + self.user_cur = 0 # 记录用户所在点 + self.cura = -1 # 记录用户选择的第一个点 + self.curb = -1 # 记录用户选择的第二个点 + self.con = 0 # 记录必经的节点数目 + + def Edge_mark_clear(self): + for edge in d.Edges: + edge[4] = 0 + G.draw() + + def Solve_display(self): + for w in frame_right.winfo_children(): + w.destroy() + # 清除右侧组件 + self.Edge_mark_clear() + cura = "无" + cur1 = -1 + curb = "无" + cur2 = -1 + lab = tk.Label(frame_right, text="自动判断相关", bg=RED, fg=BLACK, font=('微软雅黑', 20)) + lab.place(relx=0.18, rely=0.02, width=200, height=30) + for i in d.Nodes: + if i[2] == 1: + cura = str(i[1]) + cur1 = i[0] + if i[2] == 2: + curb = str(i[1]) + cur2 = i[0] + y0 = 0.1 + B = tk.Button(frame_right, text="查询该图是否联通", command=lambda: self.check()) + B.place(relx=0.1, rely=0.0 + y0, width=150, height=30) + B = tk.Button(frame_right, text="自动求解最优路径-遍历", command=lambda: self.dfs_panel()) + B.place(relx=0.1, rely=0.1 + y0, width=200, height=30) + B = tk.Button(frame_right, text="自动求解最优路径-贪心", command=lambda: self.greedy_panel()) + B.place(relx=0.1, rely=0.15 + y0, width=200, height=30) + # B.place(relx=0.1, rely=0.0 + y0, width=150, height=30) + B = tk.Button(frame_right, text="自动求解最优路径(包含非必经点)", command=lambda: self.dfs_panel_condition()) + B.place(relx=0.1, rely=0.2 + y0, width=200, height=30) + + # 当前两个节点信息 + y0 = 0.4 + laba1 = tk.Label(frame_right, text="当前节点1:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + laba2 = tk.Label(frame_right, text=f"{cura}", bg=BLUE, fg=BLACK, font=('微软雅黑', 8)) + laba1.place(relx=0.05, rely=0.02 + y0, width=80, height=30) + laba2.place(relx=0.35, rely=0.02 + y0, width=50, height=30) + labb1 = tk.Label(frame_right, text="当前节点2:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + labb2 = tk.Label(frame_right, text=f"{curb}", bg=BLUE, fg=BLACK, font=('微软雅黑', 8)) + labb1.place(relx=0.52, rely=0.02 + y0, width=80, height=30) + labb2.place(relx=0.82, rely=0.02 + y0, width=50, height=30) + B = tk.Button(frame_right, text="查询两节点是否联通", command=lambda: self.run_graph_check()) + B.place(relx=0.1, rely=0.1 + y0, width=250, height=30) + B = tk.Button(frame_right, text="查询两节点之间最优路径(时间)", command=lambda: self.auto_lowest_time()) + B.place(relx=0.1, rely=0.15 + y0, width=250, height=30) + B = tk.Button(frame_right, text="查询两节点之间最优路径(距离)", command=lambda: self.auto_lowest_cost()) + B.place(relx=0.1, rely=0.2 + y0, width=250, height=30) + B = tk.Button(frame_right, text="查询两节点之间最优路径(含必经节点)", command=lambda: self.auto_lowest_cost_condition()) + B.place(relx=0.1, rely=0.25 + y0, width=250, height=30) + + def run_graph_check(self): + a = -1 + b = -1 + # 根据已有数据获得a,b点的编号 + for node in d.Nodes: + if node[2] == 1: + a = node[0] + if node[2] == 2: + b = node[0] + if a == -1 or b == -1: + tk.messagebox.askokcancel(title='错误', message='未选择节点') + return + self.graph_check(a, b) + def graph_check(self, a, b): # 检查A点B点是否互通 + find = []# 使用并查集来检测a,b点是否互通 + for i in range(len(d.Nodes)):# 初始化并查集 + find.append(i)#使得find[i]=i + for edge in d.Edges:#根据已有的边来更新并查集 + if (edge[8] == 1 and edge[3] == 0): + continue + x = edge[1] + y = edge[2] + while not x == find[x]: + x = find[x] + while not y == find[y]: + y = find[y] + if x < y: + find[y] = x + else: + find[x] = y + x = a + y = b + while not x == find[x]:#查询a点所在集合 + x = find[x] + while not y == find[y]:#查询b点所在集合 + y = find[y] + if find[x] == find[y]:# 输出检查结果 + tk.messagebox.askokcancel(title='结果', + message='节点 ' + str(a + 1) + '与节点 ' + str(b + 1) + '互通') + else: + tk.messagebox.askokcancel(title='结果', + message='节点 ' + str(a + 1) + '与节点 ' + str(b + 1) + '不互通') + + def node_mark1(self, name): + if name >= len(d.Nodes): + N.node_404(name) + return + + for node in d.Nodes: + if node[0] == name: + node[2] = 1 + elif node[2] == 1: + node[2] = 0 + G.draw() + self.Solve_display() + + def node_mark2(self, name): + if name >= len(d.Nodes): + N.node_404(name) + return + + for node in d.Nodes: + if node[0] == name: + node[2] = 2 + elif node[2] == 2: + node[2] = 0 + G.draw() + self.Solve_display() + + def auto_lowest_time(self): # 标记遍历路径 + for w in frame_right.winfo_children(): + w.destroy() + # 清除右侧组件 + a = -1 + b = -1 + for node in d.Nodes: + if node[2] == 1: + a = node[0] + if node[2] == 2: + b = node[0] + if a == -1 or b == -1: + tk.messagebox.askokcancel(title='错误', message='未选择节点') + return + self.cura = a + self.curb = b + y0 = 0.1 + self.lowest_time_dfs() + # print(self.ans) + laba1 = tk.Label(frame_right, text="起点:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + laba2 = tk.Label(frame_right, text=f"{d.Nodes[self.cura][1]}", bg=BLUE, fg=BLACK, font=('微软雅黑', 8)) + laba1.place(relx=0.05, rely=0.02 + y0, width=80, height=30) + laba2.place(relx=0.35, rely=0.02 + y0, width=50, height=30) + labb1 = tk.Label(frame_right, text="终点:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + labb2 = tk.Label(frame_right, text=f"{d.Nodes[self.curb][1]}", bg=BLUE, fg=BLACK, font=('微软雅黑', 8)) + labb1.place(relx=0.52, rely=0.02 + y0, width=80, height=30) + labb2.place(relx=0.82, rely=0.02 + y0, width=50, height=30) + y0 += 0.1 + lab1 = tk.Label(frame_right, text="遍历路径数目:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f"{self.way_sum}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.05 + y0, width=100, height=30) + lab2.place(relx=0.5, rely=0.05 + y0, width=100, height=30) + lab1 = tk.Label(frame_right, text="求解花费时间:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f'{self.end - self.start:.4f} s', bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.10 + y0, width=100, height=30) + lab2.place(relx=0.5, rely=0.10 + y0, width=100, height=30) + lab = tk.Label(frame_right, text="自动求解时间最短路径", bg=RED, fg=BLACK, font=('微软雅黑', 20)) + lab.place(rely=0.02, width=300, height=30) + B = tk.Button(frame_right, text="返回", command=lambda: self.Solve_display()) + B.place(relx=0.1, rely=y0, width=50, height=30) + lab1 = tk.Label(frame_right, text="时间最短路径:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + + f = 0 + way = '' + for a in self.ans: + if f == 0: + f = 1 + else: + way += "->" + way += d.Nodes[a][1] + + + # way += d.Nodes[0][1] + # print(ans, "444", way) + # print (ans) + + lab2 = tk.Label(frame_right, text=f"{way}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12), wraplength=200, + justify='left') + tim = 0 + cost = 0 + for i in range(len(self.ans) - 1): + tim += d.Edges[G.node_edge(self.ans[i], self.ans[i + 1])][7] + cost += d.Edges[G.node_edge(self.ans[i], self.ans[i + 1])][6] + + + lab1.place(relx=0.1, rely=0.2 + y0, width=100, height=30) + lab2.place(relx=0.1, rely=0.25 + y0, width=200, height=100) + lab1 = tk.Label(frame_right, text="该路径时间:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f"{tim} min", bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.5 + y0, width=100, height=30) + lab2.place(relx=0.5, rely=0.5 + y0, width=100, height=30) + lab1 = tk.Label(frame_right, text="该路径距离:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f'{cost} km', bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.55 + y0, width=100, height=30) + lab2.place(relx=0.5, rely=0.55 + y0, width=100, height=30) + + def auto_lowest_cost_condition(self): # 标记遍历路径(必经) + for w in frame_right.winfo_children(): + w.destroy() + # 清除右侧组件 + a = -1 + b = -1 + for node in d.Nodes: + if node[2] == 1: + a = node[0] + if node[2] == 2: + b = node[0] + if a == -1 or b == -1: + tk.messagebox.askokcancel(title='错误', message='未选择节点') + return + self.cura = a + self.curb = b + y0 = 0.1 + self.start = time.time() + self.lowest_cost_dfs_condition() + self.end = time.time() + # print(self.ans) + laba1 = tk.Label(frame_right, text="起点:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + laba2 = tk.Label(frame_right, text=f"{d.Nodes[self.cura][1]}", bg=BLUE, fg=BLACK, font=('微软雅黑', 8)) + laba1.place(relx=0.05, rely=0.02 + y0, width=80, height=30) + laba2.place(relx=0.35, rely=0.02 + y0, width=50, height=30) + labb1 = tk.Label(frame_right, text="终点:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + labb2 = tk.Label(frame_right, text=f"{d.Nodes[self.curb][1]}", bg=BLUE, fg=BLACK, font=('微软雅黑', 8)) + labb1.place(relx=0.52, rely=0.02 + y0, width=80, height=30) + labb2.place(relx=0.82, rely=0.02 + y0, width=50, height=30) + y0 += 0.1 + lab1 = tk.Label(frame_right, text="遍历路径数目:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f"{self.way_sum}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.05 + y0, width=100, height=30) + lab2.place(relx=0.5, rely=0.05 + y0, width=100, height=30) + lab1 = tk.Label(frame_right, text="求解花费时间:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f'{self.end - self.start:.4f} s', bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.10 + y0, width=100, height=30) + lab2.place(relx=0.5, rely=0.10 + y0, width=100, height=30) + lab = tk.Label(frame_right, text="求解最短路径(含必经点)", bg=RED, fg=BLACK, font=('微软雅黑', 18)) + lab.place(rely=0.02, width=300, height=30) + B = tk.Button(frame_right, text="返回", command=lambda: self.Solve_display()) + B.place(relx=0.1, rely=y0, width=50, height=30) + lab1 = tk.Label(frame_right, text="距离最短路径:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + + if not self.check_condition(self.ans): + way = '未找到合法路径' + else: + f = 0 + way = '' + for a in self.ans: + if f == 0: + f = 1 + else: + way += "->" + way += d.Nodes[a][1] + + + + lab2 = tk.Label(frame_right, text=f"{way}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12), wraplength=200, + justify='left') + tim = 0 + cost = 0 + for i in range(len(self.ans) - 1): + tim += d.Edges[G.node_edge(self.ans[i], self.ans[i + 1])][7] + cost += d.Edges[G.node_edge(self.ans[i], self.ans[i + 1])][6] + + + lab1.place(relx=0.1, rely=0.2 + y0, width=100, height=30) + lab2.place(relx=0.1, rely=0.25 + y0, width=200, height=100) + lab1 = tk.Label(frame_right, text="该路径时间:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f"{tim} min", bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.55 + y0, width=100, height=30) + lab2.place(relx=0.5, rely=0.55 + y0, width=100, height=30) + lab1 = tk.Label(frame_right, text="该路径距离:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f'{cost} km', bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.5 + y0, width=100, height=30) + lab2.place(relx=0.5, rely=0.5 + y0, width=100, height=30) + + def auto_lowest_cost(self): # 标记遍历路径 + for w in frame_right.winfo_children(): + w.destroy() + # 清除右侧组件 + a = -1 + b = -1 + for node in d.Nodes: + if node[2] == 1: + a = node[0] + if node[2] == 2: + b = node[0] + if a == -1 or b == -1: + tk.messagebox.askokcancel(title='错误', message='未选择节点') + return + self.cura = a + self.curb = b + y0 = 0.1 + self.start = time.time() + self.lowest_cost_dfs() + self.end = time.time() + # print(self.ans) + laba1 = tk.Label(frame_right, text="起点:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + laba2 = tk.Label(frame_right, text=f"{d.Nodes[self.cura][1]}", bg=BLUE, fg=BLACK, font=('微软雅黑', 8)) + laba1.place(relx=0.05, rely=0.02 + y0, width=80, height=30) + laba2.place(relx=0.35, rely=0.02 + y0, width=50, height=30) + labb1 = tk.Label(frame_right, text="终点:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + labb2 = tk.Label(frame_right, text=f"{d.Nodes[self.curb][1]}", bg=BLUE, fg=BLACK, font=('微软雅黑', 8)) + labb1.place(relx=0.52, rely=0.02 + y0, width=80, height=30) + labb2.place(relx=0.82, rely=0.02 + y0, width=50, height=30) + y0 += 0.1 + lab1 = tk.Label(frame_right, text="遍历路径数目:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f"{self.way_sum}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.05 + y0, width=100, height=30) + lab2.place(relx=0.5, rely=0.05 + y0, width=100, height=30) + lab1 = tk.Label(frame_right, text="求解花费时间:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f'{self.end - self.start:.4f} s', bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.10 + y0, width=100, height=30) + lab2.place(relx=0.5, rely=0.10 + y0, width=100, height=30) + lab = tk.Label(frame_right, text="自动求解距离最短路径", bg=RED, fg=BLACK, font=('微软雅黑', 20)) + lab.place(rely=0.02, width=300, height=30) + B = tk.Button(frame_right, text="返回", command=lambda: self.Solve_display()) + B.place(relx=0.1, rely=y0, width=50, height=30) + lab1 = tk.Label(frame_right, text="距离最短路径:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + + f = 0 + way = '' + for a in self.ans: + if f == 0: + f = 1 + else: + way += "->" + way += d.Nodes[a][1] + + + # way += d.Nodes[0][1] + # print(ans, "444", way) + # print (ans) + + lab2 = tk.Label(frame_right, text=f"{way}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12), wraplength=200, + justify='left') + tim = 0 + cost = 0 + for i in range(len(self.ans) - 1): + tim += d.Edges[G.node_edge(self.ans[i], self.ans[i + 1])][7] + cost += d.Edges[G.node_edge(self.ans[i], self.ans[i + 1])][6] + + + lab1.place(relx=0.1, rely=0.2 + y0, width=100, height=30) + lab2.place(relx=0.1, rely=0.25 + y0, width=200, height=100) + lab1 = tk.Label(frame_right, text="该路径时间:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f"{tim} min", bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.55 + y0, width=100, height=30) + lab2.place(relx=0.5, rely=0.55 + y0, width=100, height=30) + lab1 = tk.Label(frame_right, text="该路径距离:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f'{cost} km', bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.5 + y0, width=100, height=30) + lab2.place(relx=0.5, rely=0.5 + y0, width=100, height=30) + + def dfs_panel_condition(self): + # 标记遍历路径(区分必经/非必经) + for w in frame_right.winfo_children(): + w.destroy() + # 清除右侧组件 + y0 = 0.1 + self.start = time.time() + self.node_dfs_condition() + self.end = time.time() + lab1 = tk.Label(frame_right, text="遍历路径数目:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f"{self.way_sum}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.05 + y0, width=100, height=30) + lab2.place(relx=0.5, rely=0.05 + y0, width=100, height=30) + lab1 = tk.Label(frame_right, text="求解花费时间:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f'{self.end - self.start:.4f} s', bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.10 + y0, width=100, height=30) + lab2.place(relx=0.5, rely=0.10 + y0, width=100, height=30) + lab = tk.Label(frame_right, text="求解路径(区分必经点)", bg=RED, fg=BLACK, font=('微软雅黑', 20)) + lab.place(rely=0.02, width=300, height=30) + B = tk.Button(frame_right, text="返回", command=lambda: self.Solve_display()) + B.place(relx=0.1, rely=y0, width=50, height=30) + lab1 = tk.Label(frame_right, text="最短路径:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + # 根据遍历结果输出最短路径 + way = "" + for a in self.ans: + way += d.Nodes[a][1] + way += "->" + way += d.Nodes[0][1] + if not self.check_condition(self.ans): + way = "未找到联通路径" + lab2 = tk.Label(frame_right, text=f"{way}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12), wraplength=200, + justify='left') + lab1.place(relx=0.1, rely=0.2 + y0, width=80, height=30) + lab2.place(relx=0.1, rely=0.25 + y0, width=200, height=100) + + more = 0 + way = '' + for moreans in self.mutians: + more += 1 + if more > 1: + way += '\n' + way += str(more) + ': ' + for a in moreans: + way += d.Nodes[a][1] + way += "->" + way += d.Nodes[0][1] + if more: + lab1 = tk.Label(frame_right, text="其他最短路径:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = scrolledtext.ScrolledText(frame_right, width=50, height=5, bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab2.insert('end', way) + lab2.configure(state=DISABLED) + lab1.place(relx=0.1, rely=0.2 + y0 + 0.2, width=120, height=30) + lab2.place(relx=0.1, rely=0.25 + y0 + 0.2, width=240, height=200) + + + def dfs_panel(self): # dfs面板显示 + for w in frame_right.winfo_children(): + w.destroy()# 清除右侧组件 + y0 = 0.1 + self.start = time.time()#记录开始时间 + self.node_dfs()#执行dfs搜索算法 + self.end = time.time()#记录结束时间 + lab1 = tk.Label(frame_right, text="遍历路径数目:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f"{self.way_sum}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.05 + y0, width=100, height=30) + lab2.place(relx=0.5, rely=0.05 + y0, width=100, height=30) + lab1 = tk.Label(frame_right, text="求解花费时间:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f'{self.end - self.start:.4f} s', bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.10 + y0, width=100, height=30) + lab2.place(relx=0.5, rely=0.10 + y0, width=100, height=30) + lab = tk.Label(frame_right, text="自动求解优化路径-遍历", bg=RED, fg=BLACK, font=('微软雅黑', 20)) + lab.place(rely=0.02, width=300, height=30) + B = tk.Button(frame_right, text="返回", command=lambda: self.Solve_display()) + B.place(relx=0.1, rely=y0, width=50, height=30) + lab1 = tk.Label(frame_right, text="最短路径:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + # 根据遍历结果输出最短路径 + way = "" + for a in self.ans: + way += d.Nodes[a][1] + way += "->" + way += d.Nodes[0][1] + if not len(self.ans) == len(d.Nodes): + way = "未找到联通路径" + lab2 = tk.Label(frame_right, text=f"{way}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12), wraplength=200, + justify='left') + lab1.place(relx=0.1, rely=0.2 + y0, width=80, height=30) + lab2.place(relx=0.1, rely=0.25 + y0, width=200, height=100) + # 如果有多条最短路径,则根据遍历结果依次输出 + more = 0 + way = '' + for moreans in self.mutians: + more += 1 + if more > 1: + way += '\n' + way += str(more) + ': ' + for a in moreans: + way += d.Nodes[a][1] + way += "->" + way += d.Nodes[0][1] + if more: + lab1 = tk.Label(frame_right, text="其他最短路径:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = scrolledtext.ScrolledText(frame_right, width=50, height=5,bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab2.insert('end', way) + lab2.configure(state=DISABLED) + lab1.place(relx=0.1, rely=0.2 + y0 + 0.2, width=120, height=30) + lab2.place(relx=0.1, rely=0.25 + y0 + 0.2, width=240, height=200) + + def greedy_panel(self): # 标记贪心路径 + for w in frame_right.winfo_children(): + w.destroy() + # 清除右侧组件 + + lab = tk.Label(frame_right, text="自动求解贪心路径", bg=RED, fg=BLACK, font=('微软雅黑', 20)) + lab.place(rely=0.02, width=300, height=30) + y0 = 0.1 + B = tk.Button(frame_right, text="返回", command=lambda: self.Solve_display()) + B.place(relx=0.1, rely=y0, width=50, height=30) + lab1 = tk.Label(frame_right, text="贪心法求得路径:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.2 + y0, width=150, height=30) + # 求解贪心路径 + self.node_greedy() + lab1 = tk.Label(frame_right, text="求解花费时间:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.10 + y0, width=100, height=30) + lab2 = tk.Label(frame_right, text=f'{self.end - self.start:.4f} s', bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab2.place(relx=0.5, rely=0.10 + y0, width=100, height=30) + # 显示求解获得的贪心路径 + way = "" + for a in self.ans: + way += d.Nodes[a][1] + way += "->" + + way += d.Nodes[0][1] + if not len(self.ans) == len(d.Nodes): + way = "贪心法无法找到通路" + lab2 = tk.Label(frame_right, text=f"{way}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12), wraplength=200, + justify='left') + lab2.place(relx=0.1, rely=0.25 + y0, width=200, height=100) + # 显示当前路径消耗的总成本与总时间 + dis = 0 + tim = 0 + for edge in d.Edges: + if edge[4] == True: + dis += edge[6] + tim += edge[7] + lab1 = tk.Label(frame_right, text="路径距离/成本:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f'{dis}', bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.40 + y0, width=130, height=30) + lab2.place(relx=0.5, rely=0.40 + y0, width=100, height=30) + + lab1 = tk.Label(frame_right, text="路径时间:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + lab2 = tk.Label(frame_right, text=f'{tim}', bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.45 + y0, width=130, height=30) + lab2.place(relx=0.5, rely=0.45 + y0, width=100, height=30) + + def check_condition(self, ways): + con = 0 + for w in ways: + if d.Nodes[w][4] == 1: + con += 1 + if con == self.con: + return 1 + return 0 + + def dfs_condition(self, i, ways, sum, flag): + if self.check_condition(ways) and d.Edges[G.node_edge(i, 0)][8] == 1 and d.Edges[G.node_edge(i, 0)][3] == 1: + # 如果遍历的必经节点数目符合要求,则说明这是一条符合要求的路径 + self.way_sum += 1#增加一个已搜索路径 + sum += d.Edges[G.node_edge(i, 0)][6]#更新路径花费 + if sum < self.minn:# 如果该路径的cost小于minn,则更新最短路径 + self.ans.clear()#清除原答案 + self.mutians.clear()#清除其他答案 + self.ans = ways.copy()#将当前路径加入到答案中 + self.minn = sum#更新最短路径 + elif sum == self.minn:# 如果该路径的cost等于minn,则记录在mutians中 + self.mutians.append(ways.copy())#将当前路径加入到其他路径数组中 + for j in d.Edges:# 遍历该节点的所有路径,并且对所有可能路径进行尝试 + if j[1] == i and flag[j[2]] == 0 and j[8] == 1 and j[3] == 1: + ways.append(j[2])# 如果存在一节点还没被访问过,则将其加入搜索队列 + flag[j[2]] = 1 + self.dfs_condition(j[2], ways, sum + j[6], flag) + flag[j[2]] = 0 + ways.pop() + if j[2] == i and flag[j[1]] == 0 and j[8] == 1 and j[3] == 1: + flag[j[1]] = 1 + ways.append(j[1]) + self.dfs_condition(j[1], ways, sum + j[6], flag) + ways.pop() + flag[j[1]] = 0 + return + + way_flag = 0#标记问题是否解决 + def random_way(self, i, ways, sum, flag): + if self.way_flag:#若已找到一条路径,则直接返回 + return + if len(ways) == len(d.Nodes) and d.Edges[G.node_edge(i, 0)][8] == 1\ + and d.Edges[node_edge(i, 0)][3] == 1: # 如果遍历的节点数目符合要求,则说明这是一条符合要求的路径 + sum += d.Edges[node_edge(i, 0)][6] # 更新当前路径长度 + self.way_flag = 1#将问题标记为已解决 + for way in ways: # 输出当前答案 + print(way, end=' ') + return + cur_Edges = d.Edges.copy()# 随机打乱该点能接触到的路径 + random.shuffle(cur_Edges) + for j in cur_Edges: + # 遍历该节点的所有路径,并且对所有可能路径进行尝试 + if j[1] == i and flag[j[2]] == 0 and j[8] == 1 and j[3] == 1: + # 如果存在一条路径,且对面节点还没被访问过,则将其加入搜索队列 + ways.append(j[2])#将该点加入路径 + flag[j[2]] = 1#将该点标记为已探索 + self.random_way(j[2], ways, sum + j[6], flag)# 递归搜索路径 + flag[j[2]] = 0#将该点标记为未探索 + ways.pop()#将该点移除路径 + if j[2] == i and flag[j[1]] == 0 and j[8] == 1 and j[3] == 1: + flag[j[1]] = 1#将该点加入路径 + ways.append(j[1])#将该点标记为已探索 + self.random_way(j[1], ways, sum + j[6], flag)# 递归搜索路径 + ways.pop()#将该点标记为未探索#将该点移除路径 + flag[j[1]] = 0#将该点标记为未探索 + return + def dfs(self, i, ways, sum, flag): + if len(ways) == len(d.Nodes) and d.Edges[node_edge(i, 0)][8] == 1\ + and d.Edges[node_edge(i, 0)][3] == 1: # 如果遍历的节点数目符合要求,则符合要求 + self.way_sum += 1 # 遍历路径的数目加一 + sum += d.Edges[node_edge(i, 0)][6] # 更新当前路径长度 + if sum < self.minn: # 如果该路径的cost小于minn,则更新最短路径 + self.ans.clear() # 清除ans数组 + self.mutians.clear() # 清除其他答案数组 + self.ans = ways.copy() + self.minn = sum # 更新最短路径 + elif sum == self.minn: # 如果该路径的cost等于minn,则记录在mutians中 + moreans = []#用于记录这条路径node_dfs_condition + for way in ways:#将路径途径节点逐个加入 + moreans.append(way) + self.mutians.append(moreans)# 将该路径加入答案中 + cur_Edges = d.Edges.copy()# 随机打乱该点能接触到的路径 + random.shuffle(cur_Edges) + for j in cur_Edges:# 遍历该节点的所有路径,并且对所有可能路径进行尝试 + if j[1] == i and flag[j[2]] == 0 and j[8] == 1 and j[3] == 1: + # 如果存在一条路径,且对面节点还没被访问过,则将其加入搜索队列 + ways.append(j[2])#将该点加入路径 + flag[j[2]] = 1#将该点标记为已探索 + self.dfs(j[2], ways, sum + j[6], flag)# 递归搜索路径 + flag[j[2]] = 0#将该点标记为未探索 + ways.pop()#将该点移除路径 + if j[2] == i and flag[j[1]] == 0 and j[8] == 1 and j[3] == 1: + flag[j[1]] = 1#将该点加入路径 + ways.append(j[1])#将该点标记为已探索 + self.dfs(j[1], ways, sum + j[6], flag)# 递归搜索路径 + ways.pop()#将该点标记为未探索#将该点移除路径 + flag[j[1]] = 0#将该点标记为未探索 + return + + def lcost_dfs_condition(self, i, ways, sum, flag): + if i == self.curb:# 若该节点为目标节点 + self.way_sum += 1#遍历路径数加一 + if self.check_condition(ways):# 若遍历节点数符合要求 + if sum < self.minn:#若路径花费更短,则更新答案 + self.ans = ways.copy()#更新答案 + self.minn = sum#更新最短路径 + return + + for j in d.Edges:#遍历该点能到达的所有节点 + if j[1] == i and flag[j[2]] == 0 and j[8] == 1 and j[3] == 1:#若该点未访问,则尝试访问 + ways.append(j[2])#将该点加入路径 + flag[j[2]] = 1#将该点标记为访问 + self.lcost_dfs_condition(j[2], ways, sum + j[6], flag)#递归搜索路径 + flag[j[2]] = 0#将该点移除路径 + ways.pop()#将该点移除路径 + if j[2] == i and flag[j[1]] == 0 and j[8] == 1 and j[3] == 1: + flag[j[1]] = 1#将该点标记为访问 + ways.append(j[1])#将该点加入路径 + self.lcost_dfs_condition(j[1], ways, sum + j[6], flag)#递归搜索路径 + ways.pop()#将该点移除路径 + flag[j[1]] = 0#将该点标记为未访问 + return + + def lcost_dfs(self, i, ways, sum, flag): + # print(i) + if i == self.curb: + self.way_sum += 1 + # print(ways, sum, self.minn) + if sum < self.minn: + self.ans = ways.copy() + self.minn = sum + return + + for j in d.Edges: + if j[1] == i and flag[j[2]] == 0 and j[8] == 1 and j[3] == 1: + ways.append(j[2]) + flag[j[2]] = 1 + self.lcost_dfs(j[2], ways, sum + j[6], flag) + flag[j[2]] = 0 + ways.pop() + if j[2] == i and flag[j[1]] == 0 and j[8] == 1 and j[3] == 1: + flag[j[1]] = 1 + ways.append(j[1]) + self.lcost_dfs(j[1], ways, sum + j[6], flag) + ways.pop() + flag[j[1]] = 0 + return + + def ltime_dfs(self, i, ways, sum, flag): + if i == self.curb:#若已经到达目标点,则结束搜索 + self.way_sum += 1#遍历路径加一 + if sum < self.minn:#若耗时少于最短时间 + self.ans = ways.copy()#更新答案 + self.minn = sum#更新最短时间 + return + for j in d.Edges:#遍历当前节点能到达的所有节点 + if j[1] == i and flag[j[2]] == 0 and j[8] == 1 and j[3] == 1:#若该节点未遍历则尝试该条路径 + ways.append(j[2])#将该节点加入路径 + flag[j[2]] = 1#将该节点标记为已经过 + self.ltime_dfs(j[2], ways, sum + j[7], flag)#进行递归搜索 + flag[j[2]] = 0#将该节点标记为未经过 + ways.pop() + if j[2] == i and flag[j[1]] == 0 and j[8] == 1 and j[3] == 1: + flag[j[1]] = 1#将该节点加入路径 + ways.append(j[1])#将该节点标记为已经过 + self.ltime_dfs(j[1], ways, sum + j[7], flag)#进行递归搜索 + ways.pop()#将该节点移除路径 + flag[j[1]] = 0#将该节点标记为未经过 + + def lowest_cost_dfs_condition(self): # 遍历 + # 每两个点之间只保留最短路径 + E.edge_del_all(1) + self.ans.clear() + self.way_sum = 0 + self.con = 0 + for n in d.Nodes: + if n[4]: + self.con += 1 + for edge in d.Edges: + edge[4] = False + # for i in range(len(d.Nodes)): + i = self.cura + self.minn = float("inf") + flag = [0] * len(d.Nodes) + flag[i] = 1 + self.lcost_dfs_condition(i, [i], 0, flag) + + for way in range(len(self.ans) - 1): + d.Edges[G.node_edge(self.ans[way], self.ans[way + 1])][4] = True + G.draw() + + def lowest_cost_dfs(self): # 遍历 + # 每两个点之间只保留最短路径 + E.edge_del_all(1) + # E.newedge_del_all() + self.way_sum = 0 + self.ans = [] + for edge in d.Edges: + edge[4] = False + # for i in range(len(d.Nodes)): + i = self.cura + self.minn = float("inf") + flag = [0] * len(d.Nodes) + flag[i] = 1 + self.lcost_dfs(i, [i], 0, flag) + + for way in range(len(self.ans) - 1): + d.Edges[G.node_edge(self.ans[way], self.ans[way + 1])][4] = True + G.draw() + + def lowest_time_dfs(self): # 遍历 + self.start = time.time()#记录开始时间 + E.edge_del_all(2)#每两条边只保留时间最短路径(剪枝) + self.way_sum = 0#初始化路径数目 + self.ans = []#清空答案 + for edge in d.Edges: + edge[4] = False#清空标记 + i = self.cura#初始化出发点 + self.minn = float("inf")#初始化最短路径为无穷 + flag = [0] * len(d.Nodes)#初始化已到达点 + flag[i] = 1#将出发点标记为已到达 + self.ltime_dfs(i, [i], 0, flag)#深度优先搜索确定答案 + for way in range(len(self.ans) - 1):#标记途径路径 + d.Edges[G.node_edge(self.ans[way], self.ans[way + 1])][4] = True + self.end = time.time()#记录结束时间 + G.draw()#重新绘图 + + + def node_dfs_condition(self):# 遍历 + E.edge_del_all(1)# 每两个节点之间只保留距离最短的一条 + self.con = 0#初始化经过的必经点数目 + self.way_sum = 0# 初始化遍历的节点数目 + self.ans.clear()#清除答案数组 + for node in d.Nodes:#计算必经点数量 + if node[4] == 1: + self.con += 1 + for edge in d.Edges:#清空标记 + edge[4] = False + i = 0 + self.minn = float("inf")#初始化最短路径为无穷 + flag = [0] * len(d.Nodes)#初始化已经过数组 + flag[i] = 1#将初始点标记为已经过 + self.dfs_condition(i, [0], 0, flag)#开始遍历搜索合法路径 + if not self.check_condition(self.ans):#若没找到合法路径在进行报告 + tk.messagebox.askokcancel(title='结果', message='未找到联通路径') + G.draw() + return + for way in range(len(self.ans) - 1):#逐个标记答案路径 + d.Edges[G.node_edge(self.ans[way], self.ans[way + 1])][4] = True + last = self.ans.pop()#弹出最后一个点 + d.Edges[G.node_edge(last, i)][4] = True#链接首位形成环线 + self.ans.append(last)#重新加入该点 + G.draw()#绘图 + + def node_dfs(self): # 遍历 + self.start = time.time() # 记录开始时间 + E.edge_del_all(1)# 每两个节点之间只保留距离最短的一条 + self.way_sum = 0# 初始化遍历的节点数目 + for edge in d.Edges:#清空标记 + edge[4] = False + i = 0#起始点 + self.minn = float("inf")#初始化最小值为正无穷 + flag = [0] * len(d.Nodes)#初始化已经过点 + flag[i] = 1#将起点标记为已经过 + self.dfs(i, [0], 0, flag)#使用dfs算法搜索路径 + if not len(self.ans) == len(d.Nodes):#若找不到符合要求的路径,则输出信息 + tk.messagebox.askokcancel(title='结果', message='未找到联通路径') + G.draw() + return + for way in range(len(self.ans) - 1):#标记一条路径 + d.Edges[G.node_edge(self.ans[way], self.ans[way + 1])][4] = True + last = self.ans.pop()#取出最后一个点 + d.Edges[G.node_edge(last, i)][4] = True#将起始点与最终点链接形成环线 + self.ans.append(last)#将最终点加回ans中 + self.end = time.time() # 记录结束时间 + G.draw() + + def node_greedy(self): # 贪心 + self.start = time.time()#记录开始时间 + self.ans.clear()#初始化答案列表 + E.edge_del_all(1)# 两点间仅保留距离最短路径 + for edge in d.Edges:#清空标记 + edge[4] = False + i = 0 # 起始点 + ways = [i] + flag = [0] * len(d.Nodes) # 初始化已经过点 + cur = i#初始化起始点 + sum = 0#初始化路径长度 + flag[cur] = 1#将起始点标记为已经过 + nxt = cur + for ii in range(len(d.Nodes)): + minn = float("inf")# 初始化最小值 + for j in d.Edges:# 每一步选择当前最短的链接加到路径中去 + if j[1] == cur and flag[j[2]] == 0 and j[6] < minn and j[8] == 1 and j[3] == 1: + nxt = j[2] + minn = j[6] + if j[2] == cur and flag[j[1]] == 0 and j[6] < minn and j[8] == 1 and j[3] == 1: + nxt = j[1] + minn = j[6] + if nxt != cur:#只要找到了新的路径,则加入路径中 + ways.append(nxt) + flag[nxt] = 1 + sum += minn + cur = nxt + self.ans = ways.copy() + # 如果找到的路径不合法,则表示贪心法无法求解得到合法路径 + if (not len(self.ans) == len(d.Nodes)) or (d.Edges[G.node_edge(0, ways[len(ways) - 1])][3] == 0): + tk.messagebox.askokcancel(title='结果', message='贪心法无法找到合法路径') + self.ans.clear() + return -1 + for way in range(len(ways) - 1):#标记一条路径 + d.Edges[G.node_edge(ways[way], ways[way + 1])][4] = True + d.Edges[G.node_edge(ways[len(ways) - 1], i)][4] = True#标记起点终点形成环线 + self.end = time.time()#记录结束时间 + G.draw() + # root.update() + + def check(self): # 检查是否存在最短路 + find = [] + for i in range(len(d.Nodes)): + find.append(i) + for edge in d.Edges: + if edge[8] == 1 and edge[3] == 0: + continue + x = edge[1] + y = edge[2] + while not x == find[x]: + x = find[x] + while not y == find[y]: + y = find[y] + if x < y: + find[y] = x + else: + find[x] = y + flag = 1 + for i in range(len(d.Nodes)): + if not find[i] == find[0]: + flag = 0 + + if flag: + tk.messagebox.askokcancel(title='结果', message='该图存在最短路') + else: + tk.messagebox.askokcancel(title='结果', message='该图不能完全互通') + + +if __name__ == '__main__': + G.draw() + solve = Solve() + solve.Solve_display() + mainloop() \ No newline at end of file diff --git a/WAYS.py b/WAYS.py new file mode 100644 index 0000000..7c69f65 --- /dev/null +++ b/WAYS.py @@ -0,0 +1,271 @@ +# -*- encoding: utf-8 -*- +from head import * +from NODE import * +from SOLVE import * +solve = Solve() + +N = Node() + +class Ways: + def __init__(self): + self.user_way = []#记录用户路径 + self.user_cur = 0#记录用户所在点 + self.user_flag = set()#记录用户已经过的点 + + def clear(self): + self.user_flag.clear() + self.user_way.clear() + self.user_cur = 0 + self.auto_ways() + + def check_user_best2(self): # 检查用户路径是不是最佳路径 + solve.node_dfs()#遍历计算最优路径 + + if not len(self.user_way) == len(solve.ans):# 节点个数不一样肯定不匹配 + return 0 + dis_user = 0 + dis_ans = 0 + num = len(self.user_way) + for i in range(num - 1):#计算两条路径的长度 + dis_user += d.Edges[G.node_edge(self.user_way[i], self.user_way[i + 1])][6] + dis_ans += d.Edges[G.node_edge(solve.ans[i], solve.ans[i + 1])][6] + if dis_ans == dis_user: # 用户路径长度与最短路径长度相同,用户路径是最短路 + return 1 + return 0# 匹配失败,不是最短路 + def check_user_best(self): # 检查用户路径是不是最佳路径 + # global user_way + # global ans + solve.node_dfs() + # 长度不一样肯定不匹配 + if not len(self.user_way) == len(solve.ans): + return 0 + dis_user = 0 + dis_ans = 0 + # print(user_way) + # print(ans) + num = len(self.user_way) + for i in range(num - 1): + dis_user += d.Edges[G.node_edge(self.user_way[i], self.user_way[i + 1])][6] + dis_ans += d.Edges[G.node_edge(solve.ans[i], solve.ans[i + 1])][6] + return dis_ans, dis_user + # if dis_ans == dis_user: # 匹配成功,用户路径是最短路 + # return 1 + # # 匹配失败,不是最短路 + # return 0 + + def show_best_ans(self, top, best, user): + lab1 = tk.Label(top, text="最短路径:", fg=BLACK, font=('微软雅黑', 20)) + b_way = "" + for a in solve.ans: + b_way += d.Nodes[a][1] + b_way += "->" + + b_way += d.Nodes[0][1] + y0 = 0.05 + lab2 = tk.Label(top, text=f"{b_way}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12), wraplength=200, justify='left') + lab1.place(relx=0.1, rely=0.50 + y0, width=150, height=30) + lab2.place(relx=0.4, rely=0.45 + y0, width=200, height=100) + + lab2 = tk.Label(top, text=f"最佳路径总成本:{best}\n用户路径总成本:{user}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12), wraplength=200, justify='left') + lab2.place(relx=0.4, rely=0.7 + y0, width=200, height=100) + + def show_BEST(self): + top = Toplevel(root, width=500, height=500) + top.title('判断路径是否为最短路径')# 弹出一个新的窗口来显示判断结果 + lab1 = tk.Label(top, text="用户路径:", fg=BLACK, font=('微软雅黑', 20))# 显示当前用户路径信息 + u_way = ""#生成用户路径 + for a in self.user_way: + u_way += d.Nodes[a][1] + u_way += "->" + u_way += d.Nodes[0][1]#回到起始点 + y0 = 0.05 + lab2 = tk.Label(top, text=f"{u_way}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12), wraplength=200,justify='left') + lab1.place(relx=0.1, rely=0.10 + y0, width=150, height=30) + lab2.place(relx=0.4, rely=0.05 + y0, width=200, height=100) + best, user = self.check_user_best()# 计算最优路径与用户路径的总花费 + if best == user:# 如果最优路径与用户路径的总花费相等,则说明用户路径是最短路径 + result = "用户路径是最短路径" + else:#否则说明用户路径不是最短路径 + result = "用户路径不是最短路径" + # 如果用户路径不是最短路径,则增加一个"显示最佳路径"的按钮 + B = tk.Button(top, text="显示最佳路径", command=lambda: self.show_best_ans(top, best, user)) + B.place(relx=0.6, rely=0.30 + y0, width=100, height=50) + lab = tk.Label(top, text=f"{result}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12), wraplength=200, justify='left') + lab.place(relx=0.1, rely=0.3 + y0, width=200, height=50) + + def check_user_greey(self): # 检查用户路径是不是贪心路径,不是的话返回错误点 + solve.node_greedy()# 计算贪心路径 + if not len(self.user_way) == len(solve.ans):# 路径长度不一样肯定不匹配,直接返回 + self.auto_ways() + return + num = len(self.user_way) + for i in range(num):#逐个节点进行匹配 + if not self.user_way[i] == solve.ans[i]:# 若第i位匹配失败则返回i + return i + return -1#-1表示是贪心路径 + + + def show_greddy_ans(self, top): + lab1 = tk.Label(top, text="最短路径:", fg=BLACK, font=('微软雅黑', 20)) + b_way = "" + for a in solve.ans: + b_way += d.Nodes[a][1] + b_way += "->" + + b_way += d.Nodes[0][1] + y0 = 0.05 + lab2 = tk.Label(top, text=f"{b_way}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12), wraplength=200, justify='left') + lab1.place(relx=0.1, rely=0.50 + y0, width=150, height=30) + lab2.place(relx=0.4, rely=0.45 + y0, width=200, height=100) + def show_GREDDY(self): + top = Toplevel(root, width = 500, height = 500) + top.title('判断路径是否为贪心路径')# 新建一个窗口来显示判断路径是否为贪心路径的结果 + lab1 = tk.Label(top, text="用户路径:", fg=BLACK, font=('微软雅黑', 20)) + u_way = ""# 显示用户路径 + for a in self.user_way: + u_way += d.Nodes[a][1] + u_way += "->" + u_way += d.Nodes[0][1] + y0 = 0.05 + lab2 = tk.Label(top, text=f"{u_way}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12), wraplength=200,justify='left') + lab1.place(relx=0.1, rely=0.10 + y0, width=150, height=30) + lab2.place(relx=0.4, rely=0.05 + y0, width=200, height=100) + # 逐个节点比较用户路径是否为贪心路径 + g = self.check_user_greey() + if g == -1:#如果用户路径是贪心路径则显示 + result = '用户路径是贪心路径' + else:# 若用户路径不是贪心路径,则显示在第几步时选择出错,并将该次选择的正确选择与用户实际选择显示出来 + result = '用户路径不是贪心路径' + result2 = '用户路径'+d.Nodes[self.user_way[g-1]][1]+'->'+d.Nodes[self.user_way[g]][1]+' 成本为%d\n'%d.Edges[G.node_edge(self.user_way[g-1],self.user_way[g])][6] + result2 += '贪心路径' + d.Nodes[solve.ans[g - 1]][1] + '->' + d.Nodes[solve.ans[g]][1] + ' 成本为%d\n' % d.Edges[G.node_edge(solve.ans[g-1],solve.ans[g])][6] + lab = tk.Label(top, text=result2, bg=BLUE, fg=BLACK, font=('微软雅黑', 12), wraplength=200, justify='left') + lab.place(relx=0.1, rely=0.5 + y0, width=250, height=100) + lab = tk.Label(top, text=result, bg=BLUE, fg=BLACK, font=('微软雅黑', 12), wraplength=250, justify='left') + lab.place(relx=0.1, rely=0.3 + y0, width=200, height=50) + self.auto_ways()#将结果输出到输出框 + + + # 记录用户路径(路径操作) + def way_mark_display(self): # 用户路径显示 + E.newedge_del_all(1) + for w in frame_right.winfo_children(): + w.destroy() + # 清除右侧组件 + + lab = tk.Label(frame_right, text="路径操作", bg=RED, fg=BLACK, font=('微软雅黑', 20)) + lab.place(relx=0.05, rely=0.02, width=300, height=30) + y0 = 0.1 + lab1 = tk.Label(frame_right, text="用户路径:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + + self.auto_ways() + way = "" + for a in self.user_way: + way += d.Nodes[a][1] + way += "->" + + way += d.Nodes[0][1] + + lab2 = tk.Label(frame_right, text=f"{way}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12), wraplength=200, + justify='left') + lab1.place(relx=0.1, rely=0.05 + y0, width=80, height=30) + lab2.place(relx=0.1, rely=0.15 + y0, width=200, height=100) + B = tk.Button(frame_right, text="清除路径", command=lambda: self.user_way_clear()) + B.place(relx=0.8, rely=0.15 + y0, width=50, height=30) + B = tk.Button(frame_right, text="撤销", command=lambda: self.user_way_del()) + B.place(relx=0.8, rely=0.20 + y0, width=50, height=30) + B = tk.Button(frame_right, text="检查路径", command=lambda: self.user_way_check()) + B.place(relx=0.8, rely=0.25 + y0, width=50, height=30) + B = tk.Button(frame_right, text="判断路径是否为最短路径", command=lambda: self.user_way_best()) + B.place(relx=0.1, rely=0.30 + y0, width=200, height=30) + B = tk.Button(frame_right, text="判断路径是否为贪心路径", command=lambda: self.user_way_greedy()) + B.place(relx=0.1, rely=0.35 + y0, width=200, height=30) + + def auto_ways(self): # 标记用户路径 + for w in d.Edges:#清空路径标记 + w[4] = 0 + for N in d.Nodes:#清空节点标记 + N[2] = 0 + for w in self.user_way:# 标记用户已选的点 + d.Nodes[w][2] = 5 + for w in range(len(self.user_way) - 1):# 标记用户经过的路径 + d.Edges[G.node_edge(self.user_way[w], self.user_way[w + 1])][4] = 1 + if len(set(self.user_way)) == len(d.Nodes):# 如果已经访问所有节点,自动回到初始节点 + d.Edges[G.node_edge(self.user_way[len(self.user_way) - 1], 0)][4] = 1 + G.draw()# 按照标记重新绘制图形 + + def user_way_clear(self): + self.user_flag.clear() + self.user_flag.add(0) + self.user_way.clear() + self.user_cur = 0 + self.user_way.append(0) + self.auto_ways() + self.way_mark_display() + + def user_way_del(self): # 删除路径最后一步 + if len(self.user_way) <= 1: + return + cur = self.user_way.pop() + self.user_cur = self.user_way[len(self.user_way) - 1] + self.user_flag.discard(cur) + self.auto_ways() + self.way_mark_display() + + def way_check(self): # 检查路径是否合法 + if not len(self.user_way) == len(d.Nodes):# 若用户路径没有遍历所有节点,则不合法 + return "Error: not all nodes are traversed in the user path" + for w in range(len(self.user_way) - 1):# 若用户路径不连通,则不合法 + if not d.Edges[G.node_edge(self.user_way[w], self.user_way[w + 1])][3] == 1: + return "Error: user path is not connected between node {} and node {}".format(self.user_way[w], self.user_way[w + 1]) + if d.Edges[G.node_edge(0, self.user_way[len(self.user_way) - 1])][3] == 1: + return "Valid path" + else:# 若用户路径无法回到出发点,则不合法 + return "Error: user path does not return to the starting point" + + def user_way_check(self): # 检查路径是否合法并弹窗 + check = self.way_check() + if not check == "Valid path": + result = tk.messagebox.askokcancel(title='结果', message = check) + else: + result = tk.messagebox.askokcancel(title='结果', message ='该路径合法') + + def user_way_add(self, nxt): # 用户路径操作 + # print(nxt) + if nxt in self.user_flag: + return + # 看用户选择的路径是否存在 + if d.Edges[G.node_edge(self.user_cur, nxt)][3] == 1: + # 将该点加入用户路径 + self.user_way.append(nxt) + self.user_flag.add(nxt) + self.user_cur = nxt + self.way_mark_display() + # print(user_way) + + def user_way_greedy(self): # 检查路径是否为最短路径并显示 + check = self.way_check() + if not check == "Valid path": + result = tk.messagebox.askokcancel(title='错误', message = check) + return 0 + # 若路径不合法,直接弹窗并返回 + if solve.node_greedy() == -1: + return 0 + self.show_GREDDY() + + def user_way_best(self): # 检查路径是否为最短路径并显示 + check = self.way_check() + if not check == "Valid path":# 如果用户路径不合法,则直接返回 + tk.messagebox.askokcancel(title='错误', message = check) + return 0 + # 若路径不合法,直接弹窗并返回 + self.show_BEST() + + + +if __name__ == '__main__': + G.draw() + # userG = USER_GREEDY() + # userB = USER_BSET() + W = Ways() + W.way_mark_display() + mainloop() \ No newline at end of file diff --git a/X3.py b/X3.py new file mode 100644 index 0000000..6f20d55 --- /dev/null +++ b/X3.py @@ -0,0 +1,205 @@ +# -*- encoding: utf-8 -*- +""" + @Author: packy945 + @FileName: X3.py + @DateTime: 2023/7/12 14:07 + @SoftWare: PyCharm +""" +# -*- encoding: utf-8 -*- +from head import * + +class Node: + # 标记节点按钮 + def node_mark_display(self): + for w in frame_right.winfo_children(): + w.destroy() + # 清除右侧组件 + curx = -1 + y0 = 0.1 + for i in d.Nodes: + if i[2] == 1: + curx = i[0] + lab = tk.Label(frame_right, text="节点操作", bg=RED, fg=BLACK, font=('微软雅黑', 20)) + lab.place(relx=0.18, rely=0.02, width=200, height=30) + lab1 = tk.Label(frame_right, text=f"当前共有{len(d.Nodes)}个节点", bg=RED, fg=BLACK, font=('微软雅黑', 15)) + lab1.place(relx=0.1, rely=0.0 + y0, width=200, height=30) + lab1 = tk.Label(frame_right, text="当前节点:", bg=RED, fg=BLACK, font=('微软雅黑', 12)) + if curx == -1: + text = "未选择" + else: + text = f"{d.Nodes[curx][1]}" + + lab2 = tk.Label(frame_right, text=text, bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(relx=0.1, rely=0.05 + y0, width=80, height=30) + lab2.place(relx=0.4, rely=0.05 + y0, width=80, height=30) + B = tk.Button(frame_right, text="设置标签", command=lambda: self.node_rename()) + B.place(relx=0.7, rely=0.05 + y0, width=80, height=30) + B = tk.Button(frame_right, text="删除当前节点", command=lambda: self.node_del_exact()) + B.place(relx=0.1, rely=0.1 + y0, width=150, height=30) + if d.Nodes[curx][4] == 1: + text = '设为非必经节点' + else: + text = '设为必经节点' + B = tk.Button(frame_right, text=text, command=lambda: self.dominator(curx)) + B.place(relx=0.1, rely=0.15 + y0, width=150, height=30) + B = tk.Button(frame_right, text="增加一个节点", command=lambda: self.node_add()) + B.place(relx=0.1, rely=0.25 + y0, width=150, height=30) + B = tk.Button(frame_right, text="减少一个节点", command=lambda: self.node_del()) + B.place(relx=0.1, rely=0.3 + y0, width=150, height=30) + + def dominator(self, x): + d.Nodes[x][4] ^= 1 + G.draw() + self.node_mark_display() + + def node_mark(self, name): + if name >= len(d.Nodes): + self.node_404(name) + return + + for node in d.Nodes: + if node[0] == name: + node[2] = 1 + else: + node[2] = 0 + G.draw() + self.node_mark_display() + + def node_del_exact(self): + if d.nodes_num <= 2:# 若删除节点以后节点过少,则直接返回并警告 + tk.messagebox.askokcancel(title='错误', message='节点过少') + return + flag = 0 + cur = -1 + for node in d.Nodes:# 寻找当前选定的节点 + if node[2] == 1: + cur = node[0] + flag = 1 + if flag == 0: + tk.messagebox.askokcancel(title='错误', message='未选择节点') + return + d.nodes_num -= 1#节点数目减一 + d.ang = 360 / d.nodes_num#重新计算圆心角 + nodes = d.Nodes.copy()#复制节点 + d.Nodes.clear()#清除Data中的节点 + num = 0 + for n in nodes:#逐个复制节点 + if n[0] == cur:#若是删除的节点,则不复制 + continue + n[0] = num#重新编号 + rad = math.radians(num * d.ang)#计算当前角度 + x = int(math.cos(rad) * d.R)#计算当前点x坐标(相对) + y = int(math.sin(rad) * d.R)#计算当前点y坐标(相对) + n[3] = (d.center[0] + x, d.center[1] + y)#计算绝对坐标 + d.Nodes.append(n)#将当前点加入点集合中 + num += 1 + edges = d.Edges.copy()#将原有边集复制出来 + d.Edges.clear()#删除Data中的边集 + num = 0 + for e in edges:#复制边 + if e[1] == cur or e[2] == cur:#删除的边不复制 + continue + if e[1] > cur:#修改边对应的点的编号 + e[1] -= 1 + if e[2] > cur:#修改边对应的点的编号 + e[2] -= 1 + e[0] = num#重新编号 + d.Edges.append(e)#将边加入边集中 + num += 1 + G.draw()#重新绘图 + self.node_mark_display() + + def node_rename(self): + flag = 0 + for node in d.Nodes: + if node[2] == 1: + cur = node + flag = 1 + if flag == 1: + result = tkinter.simpledialog.askstring(title='修改节点标签', prompt='请输入修改后的标签:', + initialvalue=cur[1]) + else: + tk.messagebox.askokcancel(title='错误', message='未选择节点') + return + if result: + cur[1] = result + G.draw() + self.node_mark_display() + + def node_clear(self): + for node in d.Nodes: + node[2] = False + G.draw() + + + + def node_add(self): + # 增加一个节点 + nodes = len(d.Nodes) + 1 + # 如果节点数目大于五,则将连接详细信息改为不显示 + if nodes > 5: + d.edgeinfo = 0 + self.node_init(nodes) + G.draw() + self.node_mark_display() + + def node_set(self): + node = tkinter.simpledialog.askinteger(title='修改节点数目', prompt='请输入修改后的节点数目:', + initialvalue=str(len(d.Nodes))) + if node: + self.node_init(node) + G.draw() + + def node_del(self): + if d.nodes_num <= 2: + tk.messagebox.askokcancel(title='错误', message='节点过少') + return + nodes = len(d.Nodes) - 1 + if nodes < 6: + d.edgeinfo = 1 + self.node_init(nodes) + G.draw() + self.node_mark_display() + + def node_init(self, node): + if not node: + return + if d.source == 1: + d.data(node) + elif d.source == 2: + if node > 13: + tk.messagebox.askokcancel(title='错误', message='节点过多') + return + d.HEI_data(node) + else: + if node > 13: + tk.messagebox.askokcancel(title='错误', message='节点过多') + return + d.LIAO_data(node) + if node > 5: + d.edgeinfo = 0 + else: + d.edgeinfo = 1 + + def graph_del(self): + global d + del d + + + + def node_refresh(self): + nodes = len(d.Nodes) + self.node_init(nodes) + G.draw() + self.node_mark_display() + + def node_404(self, name): + # 弹出对话框 + tk.messagebox.askokcancel(title='错误', message='该节点不存在') + # print(result) + +if __name__ == '__main__': + G.draw() + node = Node() + node.node_mark_display() + mainloop() \ No newline at end of file diff --git a/baidumap.py b/baidumap.py new file mode 100644 index 0000000..a60a521 --- /dev/null +++ b/baidumap.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +#获取城市之间的驾车距离/时间并且存入到excel表格中 +import requests, json, os, time, xlwt, sys + +flush_time = 6000 # 刷新间隔,单位秒 +file_name1 = "两地之间的开车时间.xlsx" +file_name2 = "两地之间的开车距离.xlsx" +# 预置地点列表 +address_list = [ + # "沈阳市", "大连市", "鞍山市", "抚顺市", "本溪市", "丹东市", "锦州市", "营口市", "阜新市", "辽阳市", "盘锦市", "铁岭市", "朝阳市", "葫芦岛市", +'哈尔滨市', '齐齐哈尔市', '鸡西市', '鹤岗市', '双鸭山市', '大庆市', '伊春市', '佳木斯市', '七台河市', '牡丹江市', '黑河市', '绥化市', '大兴安岭地区', + ] +workdir = os.path.dirname(os.path.realpath(sys.argv[0])) +file_path1 = os.path.join(workdir, file_name1) +file_path2 = os.path.join(workdir, file_name2) +AK = "9AfjsK2CXGuESwSb4sF3LsGhWh999Rdd" # 百度地图API认证码 + +# 获取地址的经纬度 +def getPosition(address, AK): + url = "http://api.map.baidu.com/place/v2/search" + params = { + "query": address, + "region": "全国", + "output": "json", + "ak": AK, + } + try: + res = requests.get(url, params=params) + res.raise_for_status() # 如果响应状态码不是200, 则抛出异常 + json_data = res.json() + + if json_data["status"] == 0: + lat = json_data["results"][0]["location"]["lat"] # 纬度 + lng = json_data["results"][0]["location"]["lng"] # 经度 + return (lat, lng), json_data["status"] + else: + print(json_data["message"]) + return (0, 0), json_data["status"] + except requests.RequestException as e: + print(f"Request error: {e}") + return (0, 0), -1 + except ValueError as e: + print(f"Response parsing error: {e}") + return (0, 0), -1 + +# 获取两地开车的时间 +def getTime(start, end, AK): + url = "https://api.map.baidu.com/directionlite/v1/driving" + params = { + "origin": start, + "destination": end, + "ak": AK, + } + try: + res = requests.get(url, params=params) + res.raise_for_status() # 如果响应状态码不是200, 则抛出异常 + json_data = json.loads(res.text) + + if json_data["status"] == 0: + return int(json_data['result']['routes'][0]['duration']) # 获取时间,单位s + else: + print(json_data["message"]) + return -1 + except requests.RequestException as e: + print(f"Request error: {e}") + return -1 + except ValueError as e: + print(f"Response parsing error: {e}") + return -1 + +def getDis(start, end, AK): + url = "https://api.map.baidu.com/directionlite/v1/driving" + params = { + "origin": start, + "destination": end, + "ak": AK, + } + try: + res = requests.get(url, params=params) + res.raise_for_status() # 如果响应状态码不是200, 则抛出异常 + json_data = json.loads(res.text) + + if json_data["status"] == 0: + return int(json_data["result"]["routes"][0]["distance"]) + else: + print(json_data["message"]) + return -1 + except requests.RequestException as e: + print(f"Request error: {e}") + return -1 + except ValueError as e: + print(f"Response parsing error: {e}") + return -1 + + +def calcTime(startName, endName): + start, status1 = getPosition(startName) + end, status2 = getPosition(endName) + if status1 == 0 and status2 == 0: + return round(getTime(start, end)/60, 1) # 将时间转换为分钟 + else: + return -1 + +def calcDistance(startName, endName): + start, status1 = getPosition(startName) + end, status2 = getPosition(endName) + if status1 == 0 and status2 == 0: + return round(getDis(start, end),1) + else: + return -1 +# 设置标题样式 +def set_title_style(blod=False, underline=False): + style = xlwt.XFStyle() # 初始化样式 + + font = xlwt.Font() # 为样式创建字体 + font.name = "Calibri" # 字体类型 + font.height = 20 * 11 # 20为衡量单位,11为字号 + font.bold = blod # 是否加粗 + font.underline = underline # 是否添加下划线 + + style.font = font + return style + +# 生成Excel文件 +def createExcelDis(data,file_path): + workboot = xlwt.Workbook(encoding='utf-8')# 创建workbook和sheet对象 + worksheet = workboot.add_sheet('计算两点间开车距离') # 设置工作表的名字 + for i in range(len(address_list)+1): + worksheet.col(i).width = 256 * 30 # 设置每列宽, 256为衡量单位,30表示30个字符宽度 + row0 = ["两点间开车距离(单位千米)"]+address_list# 写入Excel标题 + for i in range(len(row0)): + worksheet.write(0, i, row0[i], set_title_style(True)) + for i, line in enumerate(data): + for j, drive_dis in enumerate(line): + worksheet.write(i+1, j, str(drive_dis), set_title_style()) + workboot.save(file_path) + print("[INFO] 成功创建%s" % file_path) + +def createExcelTime(data,file_path): + # 创建workbook和sheet对象 + workboot = xlwt.Workbook(encoding='utf-8') + worksheet = workboot.add_sheet('计算两点间开车时间') # 设置工作表的名字 + for i in range(len(address_list)+1): + worksheet.col(i).width = 256 * 30 # 设置每列宽, 256为衡量单位,30表示30个字符宽度 + + # 写入Excel标题 + row0 = ["两点间开车时间(单位分钟)"]+address_list + for i in range(len(row0)): + worksheet.write(0, i, row0[i], set_title_style(True)) + # 写入查询百度地图api获取的数据 + for i,line in enumerate(data): + for j,drive_time in enumerate(line): + worksheet.write(i+1, j, str(drive_time), set_title_style()) + workboot.save(file_path) + print("[INFO] 成功创建%s" % file_path) + +# 生成开车时间矩阵信息 +def generateTimeMatrix(flush_time,file_path): + while True: + matrix_list = [] # 以矩阵的方式来存放两地之间的开车时间 + alist = [] # 存放横坐标的值 + print("[INFO] 开始计算两地之间的开车时间,每隔%s秒刷新一次..." % flush_time) + for start in address_list: # 起始位置作为纵坐标 + alist.append(start) + for end in address_list: # 终点位置作为横坐标 + dt = calcTime(start, end) + alist.append(dt) + matrix_list.append(alist) + alist = [] + createExcelTime(matrix_list,file_path) + time.sleep(flush_time) + +# 生成开车时间矩阵信息 +def generateDistanceMatrix(flush_time,file_path): + while True: + matrix_list = [] # 以矩阵的方式来存放两地之间的开车距离 + alist = [] # 存放横坐标的值 + print("[INFO] 开始计算两地之间的开车距离,每隔%s秒刷新一次..." % flush_time) + for start in address_list: # 起始位置作为纵坐标 + alist.append(start) + for end in address_list: # 终点位置作为横坐标 + dt = calcDistance(start, end) + alist.append(dt) + matrix_list.append(alist) + alist = [] + createExcelDis(matrix_list,file_path) + time.sleep(flush_time) + +if __name__ == "__main__": + try: + # 时间 + generateTimeMatrix(flush_time, file_path1) + # 距离 + generateTimeMatrix(flush_time, file_path2) + except Exception as e: + print('ERROR:%s' % e) diff --git a/data.py b/data.py new file mode 100644 index 0000000..c8279d6 --- /dev/null +++ b/data.py @@ -0,0 +1,428 @@ +# -*- encoding: utf-8 -*- + +import math +import random +import pandas as pd +from collections import Counter + +def _init(): + global _global_dict + _global_dict={} + + + +class Data(): + def __init__(self, source :int, num: int): + self.source = source + # 数据来源 + # 1随机 2黑龙江省 3辽宁省 + # 默认为1 + self.edgeinfo = 1 + # 是否显示详情 + # 1显示 0不显示 + # 默认为1 + self.heidata = pd.read_excel("hei/data.xlsx") # 黑龙江省各市信息 + self.heitime = pd.read_excel("hei/time.xlsx") # 黑龙江省各市通行时间 + self.heidis = pd.read_excel("hei/distance.xlsx") # 黑龙江省各市通行距离 + self.liaodata = pd.read_excel("liao/data.xlsx") # 辽宁省各市信息 + self.liaotime = pd.read_excel("liao/time.xlsx") # 辽宁省各市通行时间 + self.liaodis = pd.read_excel("liao/distance.xlsx") # 辽宁省各市通行距离 + if self.source == 1: + self.data(num) + elif self.source == 2: + self.HEI_data(num) + elif self.source == 3: + self.LIAO_data(num) + + + def get_liaotime(self, i, j): + # print(self.heidata.iloc[i, 0]) + # print(self.heidata.iloc[j, 0]) + # print(self.heitime.iloc[i, j + 1]) + return math.floor(self.liaotime.iloc[i, j + 1]) + + def get_liaodis(self, i, j): + # print(self.heidata.iloc[i, 0]) + # print(self.heidata.iloc[j, 0]) + # print(self.heidis.iloc[i, j + 1]) + return math.floor(self.liaodis.iloc[i, j + 1] / 1000) + + def get_heitime(self, i, j): + # print(self.heidata.iloc[i, 0]) + # print(self.heidata.iloc[j, 0]) + # print(self.heitime.iloc[i, j + 1]) + return math.floor(self.heitime.iloc[i, j + 1]) + + def get_heidis(self, i, j): + # print(self.heidata.iloc[i, 0]) + # print(self.heidata.iloc[j, 0]) + # print(self.heidis.iloc[i, j + 1]) + return math.floor(self.heidis.iloc[i, j + 1] / 1000) + + def data(self, num: int): + if num <= 0: + raise ValueError("num must be a positive integer") + self.edgeinfo = 1 + # 是否显示详情 + # 1显示 0不显示 + # 默认为1 + self.nodes_num = num # 节点个数 + self.ang = 360 / self.nodes_num # 圆心顶点角度 + self.R = 300 # 外接圆半径 + self.bc = 2 * self.R * math.sin(math.pi / self.nodes_num) # 节点之间的正多边形距离 + self.canvas_len = int(2 * self.R + 80) # 画布边长 + self.center = (self.canvas_len // 2, self.canvas_len // 2) # 画布中心点坐标 + self.coordinate = self.coord_creat() # 纯节点坐标 + self.Nodes = self.nodes_creat() # 创建节点列表 + self.Edges = self.edges_creat() # 创建第一条连接 + self.edge_add(2) # 创建第2条连接 + self.edge_add(3) # 创建第3条连接 + + def HEI_data(self, num: int): + self.edgeinfo = 1 + # 是否显示详情 + # 1显示 0不显示 + # 默认为1 + self.number = [] + for i in range(13): + self.number.append(i) + self.name = random.sample(self.number, num) + self.nodes_num = num # 节点个数 + self.ang = 360 / self.nodes_num # 圆心顶点角度 + self.R = 300 # 外接圆半径 + self.bc = 2 * self.R * math.sin(math.pi / self.nodes_num) # 节点之间的正多边形距离 + self.canvas_len = int(2 * self.R + 80) # 画布边长 + self.center = (self.canvas_len // 2, self.canvas_len // 2) # 画布中心点 + self.coordinate = self.coord_creat() # 纯节点坐标 + self.Nodes = self.JI_nodes_creat() # 节点列表 + self.Edges = self.JI_edges_creat() + self.JI_edge_add(2) + self.JI_edge_add(3) + + def LIAO_data(self, num: int): + self.edgeinfo = 1 + # 是否显示详情 + # 1显示 0不显示 + # 默认为1 + self.number = [] + for i in range(13): + self.number.append(i) + self.name = random.sample(self.number, num) + self.nodes_num = num # 节点个数 + self.ang = 360 / self.nodes_num # 圆心顶点角度 + self.R = 300 # 外接圆半径 + self.bc = 2 * self.R * math.sin(math.pi / self.nodes_num) # 节点之间的正多边形距离 + self.canvas_len = int(2 * self.R + 80) # 画布边长 + self.center = (self.canvas_len // 2, self.canvas_len // 2) # 画布中心点 + self.coordinate = self.coord_creat() # 纯节点坐标 + self.Nodes = self.LIAO_nodes_creat() # 节点列表 + self.Edges = self.LIAO_edges_creat() + self.LIAO_edge_add(2) + self.LIAO_edge_add(3) + + def LIAO_nodes_creat(self, n_sum=None): + """Nodes[]={<节点对象编号,节点标签,节点类别,节点坐标, 是否为必经节点(默认必经)>}""" + if n_sum == None: + n_sum = self.nodes_num + nodes = [] + miny = float("inf") + minx = float("inf") + maxx = 0 + maxy = 0 + + for i in self.name: + maxx = max(maxx, self.liaodata.iloc[i, 2]) + minx = min(minx, self.liaodata.iloc[i, 2]) + maxy = max(maxy, self.liaodata.iloc[i, 1]) + miny = min(miny, self.liaodata.iloc[i, 1]) + lenx = maxx - minx + leny = maxy - miny + Ox = (maxx + minx) / 2 + Oy = (maxy + miny) / 2 + + x0 = self.center[0] + y0 = self.center[1] + for i in range(n_sum): + ix = self.liaodata.iloc[self.name[i], 2] + iy = self.liaodata.iloc[self.name[i], 1] + x = int(((ix - Ox) / lenx) * 550) + y = -int(((iy - Oy) / leny) * 550) + + name = self.liaodata.iloc[self.name[i], 0] + # name=''+str(i+1) + mark = 0 + dominator = 1 + nodes.append([i, name, mark, (x0+x, y0+y), dominator]) + return nodes + + def LIAO_edges_creat(self): + ''' + 路径创建 + Edges[] = { < 连接对象编号,节点对象1编号,节点对象2编号,连接序号,连接是否可用,连接标签,连接的距离 / 成本,连接的时间 >} + ''' + + edges = [] # 所有链接集合 + ser = 0 # 链接对象编号 + nodes = self.Nodes.copy() # 复制节点对象 + nodes1 = self.Nodes.copy() # 复制节点对象 + + for node in nodes: # 遍历节点对象 + if node in nodes1: # 删除nodes1中当期遍历的节点信息 + nodes1.remove(node) + for node1 in nodes1: # 遍历删除后的节点信息 + # Edges[] = { < 连接序号,节点对象1编号,节点对象2编号,链接是否可用(序号大于1),连接是否标记,连接标签,连接的距离 / 成本,连接的时间,连接序号 >} + n1 = node[0] # 节点对象编号1 + n2 = node1[0] # 节点对象编号2 + seq = 1 # 链接序号 + mark = False # 连接是否标记 + tag = self.liaodis.iloc[self.name[n1], 0] + '-' + self.liaodis.iloc[self.name[n2], 0] + # tag = f"{n1+1}-{n2+1}" # 链接标签 + dist_c = self.get_liaodis(n1, n2) + # dist_c = random.randint(30,120) # 距离成本 + time_c = self.get_liaotime(n1, n2) + # time_c = random.randint(1,30) # 链接的时间 + enable = 1 # 连接是否可用 + edges.append([ser, n1, n2, enable, mark, tag, dist_c, time_c, seq]) + ser += 1 + return edges + + def LIAO_edge_add(self, no): + nodes = self.Nodes.copy() # 复制节点对象 + nodes1 = self.Nodes.copy() # 复制节点对象 + for node in nodes: # 遍历节点对象 + if node in nodes1: # 删除nodes1中当期遍历的节点信息 + nodes1.remove(node) + + for node1 in nodes1: # 遍历删除后的节点信息 + # Edges[] = { < 连接序号,节点对象1编号,节点对象2编号,链接是否显示(序号大于1),连接是否标记,连接标签,连接的距离 / 成本,连接的时间,连接序号 >} + ser = len(self.Edges) # 链接序号 + n1 = node[0] # 节点对象编号1 + n2 = node1[0] # 节点对象编号2 + show = 0 + mark = False # 连接是否标记 + tag = f"{self.liaodis.iloc[self.name[n1], 0]}-{self.liaodis.iloc[self.name[n2], 0]}-{no}" # 链接标签 + # tag = f"{n1 + 1}-{n2 + 1}-{no}" # 链接标签 + dist_c = self.get_liaodis(n1, n2) + # dist_c = random.randint(30,120) # 距离成本 + time_c = self.get_liaotime(n1, n2) + # time_c = random.randint(1,30) # 链接的时间 + seq = no # 连接序号 + self.Edges.append([ser, n1, n2, show, mark, tag, dist_c, time_c, seq]) + + def JI_nodes_creat(self, n_sum=None): + """Nodes[]={<节点对象编号,节点标签,节点类别,节点坐标, 是否为必经节点(默认必经)>>}""" + if n_sum == None: + n_sum = self.nodes_num + nodes = [] + miny = float("inf") + minx = float("inf") + maxx = 0 + maxy = 0 + + for i in self.name: + # print(i, self.heidis.iloc[i, 0]) + # print(self.heidata.iloc[i, 0], self.heidata.iloc[i, 1], self.heidata.iloc[i, 2]) + maxx = max(maxx, self.heidata.iloc[i, 2]) + minx = min(minx, self.heidata.iloc[i, 2]) + maxy = max(maxy, self.heidata.iloc[i, 1]) + miny = min(miny, self.heidata.iloc[i, 1]) + # print(maxx, maxy, minx, miny) + lenx = maxx - minx + leny = maxy - miny + Ox = (maxx + minx) / 2 + Oy = (maxy + miny) / 2 + + R = self.R + x0 = self.center[0] + y0 = self.center[1] + for i in range(n_sum): + # rad = math.radians(i*self.ang) + # x = int(math.cos(rad)*R) + # y = int(math.sin(rad)*R) + ix = self.heidata.iloc[self.name[i], 2] + iy = self.heidata.iloc[self.name[i], 1] + # print(int(math.cos(rad)*R)) + # print(((ix - Ox) / lenx) * 300) + x = int(((ix - Ox) / lenx) * 550) + y = -int(((iy - Oy) / leny) * 550) + name = self.heidata.iloc[self.name[i], 0] + # name=''+str(i+1) + mark = 0 + dominator = 1 + nodes.append([i, name, mark, (x0+x, y0+y), dominator]) + return nodes + + def JI_edges_creat(self): + ''' + 路径创建 + Edges[] = { < 连接对象编号,节点对象1编号,节点对象2编号,连接序号,连接是否可用,连接标签,连接的距离 / 成本,连接的时间 >} + ''' + + edges = [] # 所有链接集合 + ser = 0 # 链接对象编号 + nodes = self.Nodes.copy() # 复制节点对象 + nodes1 = self.Nodes.copy() # 复制节点对象 + + for node in nodes: # 遍历节点对象 + if node in nodes1: # 删除nodes1中当期遍历的节点信息 + nodes1.remove(node) + + for node1 in nodes1: # 遍历删除后的节点信息 + for i in range(random.randint(1,1)): + # Edges[] = { < 连接序号,节点对象1编号,节点对象2编号,链接是否可用(序号大于1),连接是否标记,连接标签,连接的距离 / 成本,连接的时间,连接序号 >} + + n1 = node[0] # 节点对象编号1 + n2 = node1[0] # 节点对象编号2 + seq = 1 # 链接序号 + mark = False # 连接是否标记 + tag = self.heidis.iloc[self.name[n1], 0] + '-' + self.heidis.iloc[self.name[n2], 0] + # tag = f"{n1+1}-{n2+1}" # 链接标签 + dist_c = self.get_heidis(n1, n2) + # dist_c = random.randint(30,120) # 距离成本 + time_c = self.get_heitime(n1, n2) + # time_c = random.randint(1,30) # 链接的时间 + enable = 1 # 连接是否可用 + edges.append([ser, n1, n2, enable, mark, tag, dist_c, time_c, seq]) + ser += 1 + return edges + + def JI_edge_add(self, no): + nodes = self.Nodes.copy() # 复制节点对象 + nodes1 = self.Nodes.copy() # 复制节点对象 + for node in nodes: # 遍历节点对象 + if node in nodes1: # 删除nodes1中当期遍历的节点信息 + nodes1.remove(node) + + for node1 in nodes1: # 遍历删除后的节点信息 + # Edges[] = { < 连接序号,节点对象1编号,节点对象2编号,链接是否显示(序号大于1),连接是否标记,连接标签,连接的距离 / 成本,连接的时间,连接序号 >} + ser = len(self.Edges) # 链接序号 + n1 = node[0] # 节点对象编号1 + n2 = node1[0] # 节点对象编号2 + show = 0 + mark = False # 连接是否标记 + tag = f"{self.heidis.iloc[self.name[n1], 0]}-{self.heidis.iloc[self.name[n2], 0]}-{no}" # 链接标签 + # tag = f"{n1 + 1}-{n2 + 1}-{no}" # 链接标签 + dist_c = self.get_heidis(n1, n2) + # dist_c = random.randint(30,120) # 距离成本 + time_c = self.get_heitime(n1, n2) + # time_c = random.randint(1,30) # 链接的时间 + seq = no # 连接序号 + self.Edges.append([ser, n1, n2, show, mark, tag, dist_c, time_c, seq]) + + + def coord_creat(self): + '''返回每个节点的坐标''' + coordinate = [] + x0 = self.center[0] + y0 = self.center[1] + for i in range(self.nodes_num): + rad = math.radians(i*self.ang) + x = int(math.cos(rad)*self.R) + y = int(math.sin(rad)*self.R) + coordinate.append((x0+x,y0+y)) + return coordinate + + def nodes_creat(self, n_sum= None): + """Nodes[]={<节点对象编号,节点标签,节点类别,节点坐标, 是否为必经节点(默认必经)>}""" + if n_sum == None: + n_sum = self.nodes_num + nodes = []#初始化node表 + # 设置画布中心点坐标x0,y0 + x0 = self.center[0] + y0 = self.center[1] + for i in range(n_sum):# 通过几何运算得到多边形各个顶点坐标 + rad = math.radians(i * self.ang)# 计算第i个点的弧度 + x = int(math.cos(rad) * self.R)# 计算第i个顶点x坐标 + y = int(math.sin(rad) * self.R)# 计算第i个顶点y坐标 + name = '' + str(i + 1)# 给第i个顶点命名 + mark = 0#节点为未标记 + dominator = 1#设置为必经节点 + nodes.append([i, name, mark, (x0 + x, y0 + y), dominator])#将当前节点加入node中 + return nodes + + + def edges_creat(self): + ''' + 路径创建 + Edges[] = { < 连接对象编号,节点对象1编号,节点对象2编号,连接是否存在,连接是否标记,连接标签,连接的距离 / 成本,连接的时间,连接序号 >} + ''' + edges = [] # 初始化所有链接集合 + ser = 0 # 初始化链接对象编号 + nodes = self.Nodes.copy() # 复制节点对象 + nodes1 = self.Nodes.copy() # 复制节点对象 + for node in nodes: # 遍历节点对象 + if node in nodes1: # 删除nodes1中当期遍历的节点信息 + nodes1.remove(node) + for node1 in nodes1: # 遍历删除后的节点信息 + # Edges[] = { < 连接序号,节点对象1编号,节点对象2编号,链接是否可用(序号大于1),连接是否标记,连接标签,连接的距离 / 成本,连接的时间,连接序号 >} + n1 = node[0] # 节点对象编号1 + n2 = node1[0] # 节点对象编号2 + seq = 1 # 链接序号 + mark = False # 连接是否标记 + tag = f"{n1+1}-{n2+1}" # 链接标签 + dist_c = random.randint(10, 120) # 随机生成距离成本 + time_c = random.randint(10, 120) # 随机生成链接的时间 + enable = 1 # 连接是否可用 + if dist_c >= 100 or time_c >= 100: # 设置某些节点为不显示 + enable = 0 + edges.append([ser, n1, n2, enable, mark, tag, dist_c, time_c, seq]) # 将连接加入到边的集合中 + ser+=1# 计数加一 + return edges + + def node_count(self, node_num:tuple, node_co:list): + for node in node_num: + node_co.append(node) + + + def path_creat(self): + node_co = {} # 节点统计, + for node in self.Nodes: + node_co[node[0]] = 0 + print(node_co) + + for edge in self.Edges: + for num in node_co.keys(): + if node_co[num] <=1: + if edge[1] == num or edge[2]== num: + node_co[num]+=1 + print((edge[1],edge[2])) + print(node_co) # 每个节点出现的次数 + + def node_co(self,key): # 通过节点编号返回编号的坐标 + """通过节点编号返回编号的坐标""" + nodes = self.Nodes + for n in nodes: + if n[0] == key: + return n[3] + + def edge_add(self, no): + nodes = self.Nodes.copy() # 复制节点对象 + nodes1 = self.Nodes.copy() # 复制节点对象 + for node in nodes: # 遍历节点对象 + if node in nodes1: # 删除nodes1中当期遍历的节点信息 + nodes1.remove(node) + + for node1 in nodes1: # 遍历删除后的节点信息 + # Edges[] = { < 连接序号,节点对象1编号,节点对象2编号,链接是否显示(序号大于1),连接是否标记,连接标签,连接的距离 / 成本,连接的时间,连接序号 >} + ser = len(self.Edges) # 链接序号 + n1 = node[0] # 节点对象编号1 + n2 = node1[0] # 节点对象编号2 + show = 0 + mark = False # 连接是否标记 + tag = f"{n1 + 1}-{n2 + 1}-{no}" # 链接标签 + dist_c = random.randint(30, 100) # 距离成本 + time_c = random.randint(1, 30) # 链接的时间 + enable = no # 连接是否可用 + self.Edges.append([ser, n1, n2, show, mark, tag, dist_c, time_c, enable]) + + + + + +if __name__ == '__main__': + + d = Data(1, 5) + d.path_creat() + + #print(d.Edges) + diff --git a/head.py b/head.py new file mode 100644 index 0000000..0a505c0 --- /dev/null +++ b/head.py @@ -0,0 +1,238 @@ +# -*- encoding: utf-8 -*- +import math +import queue +import time +import tkinter as tk +from tkinter import * +from tkinter import scrolledtext +import tkinter.messagebox +import tkinter.simpledialog +from data import * + +BLUE = "#0080FF" +BLACK = "#000000" +RED = "#FFAAAA" +YELLOW = "#FFFACD" +LINE = '#c8d2c8' +GREY = '#070b19' +GREEN = '#5ba585' +NODE = '#33a8cd' +ZERO = 'gold' + +nodes = 6#设置初始节点数量 + +d = Data(1, nodes) + +root = tk.Tk() #设置主界面 +root.title("旅行商问题") # 设置标题 +root.geometry(f"{d.canvas_len + 370}x{d.canvas_len + 100}") # 设置大小 +root.resizable(0,0) # 设置不能调整显示边框 + +frame = tk.Frame(root, padx=20, pady=20, width=d.canvas_len, height=d.canvas_len + 50) +frame.grid() # 绘制显示框 + +frame_top = tk.Frame(frame, width=d.canvas_len, height=50) +frame_top.grid(row=0, column=0) # 绘制信息输出栏 + +cv = canvas = tk.Canvas(frame, bg='white', bd=2, relief="sunken", width=d.canvas_len, height=d.canvas_len) +canvas.grid(row=1, column=0)#放置绘图Canvas画布 + +frame_right = tk.Frame(root, bg=RED, width=300, height=d.canvas_len + 50)# 右边栏 +frame_right.grid(row=0, column=1) # 右边栏 + + +def dir2(x, y): # 计算两点间距离 + return (x[0] - y[0]) * (x[0] - y[0]) + (x[1] - y[1]) * (x[1] - y[1]) + + +main_menu = tk.Menu(root) +root.config(menu=main_menu) + + +def node_edge(n1, n2, no=1): # 根据点的编号找边的编号 + if n1 > n2:#为了防止充分编号,让n1小于n2 + n1, n2 = n2, n1 + for e in d.Edges:#遍历所有路径,找到符合要求的返回 + if e[1] == n1 and e[2] == n2 and e[8] == no: + return e[0] + return -1#若找不到,则返回-1 + +class Graph: + def draw(self): + cv.delete('all')#清空画布 + dis, tim = self.edges_show(cv, d.Edges)#绘制边 + self.lab_show(frame_top, len(d.Nodes), tim, dis)#显示边信息 + self.nodes_show(cv)#绘制点 + cv.update()#更新画布 + + def lab_show(self, frame: tk.Frame, nodes: int, time: int, distance: int): + labs = ["节点数目", "时间", "距离(成本)"] + x0 = d.canvas_len // 3 + for i in range(len(labs)): + lab1 = tk.Label(frame, text=labs[i], fg=BLACK, font=('微软雅黑', 12)) + if i == 0: + lab2 = tk.Label(frame, text=f"{nodes}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + elif i == 1: + lab2 = tk.Label(frame, text=f"{time}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + else: + lab2 = tk.Label(frame, text=f"{distance}", bg=BLUE, fg=BLACK, font=('微软雅黑', 12)) + lab1.place(x=10 + x0 * i, y=10, width=80, height=30) + lab2.place(x=10 + x0 * i + 80, y=10, width=80, height=30) + lab1 = tk.Label(frame, text='分钟', fg=BLACK, font=('微软雅黑', 12)) + lab1.place(x=170 + x0, y=10, width=50, height=30) + lab1 = tk.Label(frame, text='千米', fg=BLACK, font=('微软雅黑', 12)) + lab1.place(x=170 + x0 * 2, y=10, width=50, height=30) + + def nodes_show(self, cv: tk.Canvas): + """ + 显示节点 + :param cv: tkcanvas对象 + :return: + """ + COL = NODE# 初始化节点颜色 + for i in d.Nodes:# 遍历每一个节点 + x, y = i[3] #记录该节点坐标 + if i[2] == 1 or i[2] == 2:# 如果节点被标记,则将节点标为红色 + COL = RED + elif i[0] == 0:# 如果节点为起始节点,则将节点标记为特殊颜色 + COL = ZERO + elif i[2] == 5:# 如果节点已经被访问,则将节点标记(用户路径功能) + COL = 'gold' + else:#否则则使用初始颜色 + COL = NODE + if i[4] == 1:# 如果是必经节点,则加黑色边框 + w = 1 + else:# 如果是非必经节点,则没有边框 + w = 0 + # 根据坐标,圆的颜色与是否有边框绘制圆圈来表示节点 + cv.create_oval(x - 20, y - 20, x + 20, y + 20, fill=COL, width=w,)# outline='#ee28a3') + if d.source == 1:# 根据节点信息将节点的标签显示在节点上 + cv.create_text(x, y, text=f'{i[1]}', fill=GREY, font=('华文楷体', 24)) + else: + cv.create_text(x, y, text=f'{i[1]}', fill=GREY, font=('华文楷体', 18)) + cv.update() + + def edges_show(self, cv: tk.Canvas, edges: d.Edges): + """ + 显示链接 + :param cv: tkcanvas对象 + :return: + """ + distance = 0 # 初始化被标记的线的总路径 + time1 = 0 # 初始化被标记的线的总时间 + for edge in edges: + node_1 = d.node_co(edge[1]) # 链接线编号对应的坐标1 + node_2 = d.node_co(edge[2]) # 链接线编号对应的坐标2 + if edge[8] == 2 and edge[3] == 1: # 若该链接为两点间第二条连线 + self.more_edge_show(2, edge) + elif edge[8] == 3 and edge[3] == 1: # 若为两点间第3条连线 + self.more_edge_show(3, edge) + if edge[8] == 1 and edge[3] == 1:# 若为两点间第1条连线且该连接存在 + self.edge_info(cv, f'{edge[5]} {edge[6]} {edge[7]}', node_1, node_2) + point = [node_1, node_2] + if edge[4] == 1 and edge[8] == 1 and edge[3] == 1:# 如果路径被标记,则用绿色绘制 + cv.create_line(point, fill=GREEN, width=4) + distance += edge[6]# 更新总路径 + time1 += edge[7]# 更新总时间 + elif edge[8] == 1 and edge[3] == 1:# 如果是节点之间的第一条线,则用正常颜色标记 + cv.create_line(point, fill=LINE, width=2) + if d.Nodes[edge[1]][2] + d.Nodes[edge[2]][2] == 3:# 若该线被用户选中,则用蓝色虚线标记 + cv.create_line(point, fill=BLUE, width=5, dash=(4, 14)) + return (distance, time1)# 返回标记路径的总时间与路程 + + def more_edge_show(self, no, E): + # print(n1,n2) + n1 = E[1] + n2 = E[2] + node_1 = d.node_co(n1) + node_2 = d.node_co(n2) + (n1x, n1y) = node_1 + (n2x, n2y) = node_2 + n0x = (n1x + n2x) / 2 + n0y = (n1y + n2y) / 2 + (Ox, Oy) = d.center + x = 30 # 新路径距原路径距离 + if no == 2: + if not Ox - n0x == 0: + k = (Oy - n0y) / (Ox - n0x) + + n3x = n0x + x * math.cos(math.atan(k)) + n3y = n0y + x * math.sin(math.atan(k)) + else: + n3x = n0x + n3y = n0y + x + elif no == 3: + if not Ox - n0x == 0: + k = (Oy - n0y) / (Ox - n0x) + + n3x = n0x - x * math.cos(math.atan(k)) + n3y = n0y - x * math.sin(math.atan(k)) + else: + n3x = n0x + n3y = n0y - x + + self.moreedge_info(cv, f'{E[5]} {E[6]} {E[7]}', node_1, node_2, (n3x, n3y), no) + cv.create_line((n1x, n1y), (n3x, n3y), fill=LINE, width=2) + cv.create_line((n2x, n2y), (n3x, n3y), fill=LINE, width=2) + + def node_edge(self, a, b): # 根据点的编号找边的编号 + if a > b: + x = a + a = b + b = x + return int(a * (2 * len(d.Nodes) - a - 3) / 2 + b - 1) + + def moreedge_info(self, cv: tk.Canvas, info: str, n1: tuple, n2: tuple, n3: tuple, no): + + if d.edgeinfo == 0: + return + if no == 2: + flag = 1 + else: + flag = -1 + x = n3[0] + y = n3[1] + + if (n2[1] - n1[1]) != 0: # 斜率为非0度时的显示 + reat = math.atan((n2[0] - n1[0]) / (n2[1] - n1[1])) # 根据斜率计算弧度 + ang = round(math.degrees(reat)) + 90 # 根据弧度转角度 + if ang > 89: # 斜度大于90度调整坐标 + cv.create_text(x + 15 * flag, y, text=f'{info}', fill="black", font=('微软雅黑', 12), angle=ang) + # cv.create_text(x, y, text=f'{i[1]}', fill="red", font=('微软雅黑', 24)) + else: + cv.create_text(x, y + 15 * flag, text=f'{info}', fill="black", font=('微软雅黑', 12), angle=ang) + else: + ang = round(math.degrees(0)) # 根据弧度转角度 + cv.create_text(x - 30 * flag, y + 10 * flag, text=f'{info}', fill="black", font=('微软雅黑', 12), angle=ang) + + def edge_info(self, cv: tk.Canvas, info: str, n1: tuple, n2: tuple): + ''' + 取连线中点坐标,显示info的信息 + :param info: 连线信息 + :param center: 画布中心点 + :param n1: 连线端点1 + :param n2: 连线端点2 + :return: None + ''' + if d.edgeinfo == 0: #若设置为不显示则直接返回 + return + x = (n1[0] - n2[0]) // 2 + n2[0]#计算中点x坐标 + y = (n1[1] - n2[1]) // 2 + n2[1]#计算中点y坐标 + if (n2[1] - n1[1]) != 0: # 斜率为非0度时的显示 + reat = math.atan((n2[0] - n1[0]) / (n2[1] - n1[1])) # 根据斜率计算弧度 + ang = round(math.degrees(reat)) + 90 # 根据弧度转角度 + if ang > 89: # 斜度大于90度调整坐标 + text_x, text_y = x + 15, y + else:# 斜度大于90度调整坐标 + text_x, text_y = x, y + 15 + else:# 斜率为0度时的显示 + ang = round(math.degrees(0)) # 根据弧度转角度 + text_x, text_y = x - 30, y + 10 + cv.create_text(text_x, text_y, text=f'{info}', fill="black", font=('微软雅黑', 12), angle=ang)#根据信息显示文字 + + +G = Graph() +if __name__ == '__main__': + # G = Graph() + G.draw() + mainloop() diff --git a/hei/data.xlsx b/hei/data.xlsx new file mode 100644 index 0000000..f0d7d8f Binary files /dev/null and b/hei/data.xlsx differ diff --git a/hei/distance.xlsx b/hei/distance.xlsx new file mode 100644 index 0000000..4486eb3 Binary files /dev/null and b/hei/distance.xlsx differ diff --git a/hei/time.xlsx b/hei/time.xlsx new file mode 100644 index 0000000..b36e071 Binary files /dev/null and b/hei/time.xlsx differ diff --git a/liao/data.xlsx b/liao/data.xlsx new file mode 100644 index 0000000..fd719c4 Binary files /dev/null and b/liao/data.xlsx differ diff --git a/liao/distance.xlsx b/liao/distance.xlsx new file mode 100644 index 0000000..75b6a3b Binary files /dev/null and b/liao/distance.xlsx differ diff --git a/liao/time.xlsx b/liao/time.xlsx new file mode 100644 index 0000000..bf01108 Binary files /dev/null and b/liao/time.xlsx differ diff --git a/main.py b/main.py new file mode 100644 index 0000000..2871150 --- /dev/null +++ b/main.py @@ -0,0 +1,248 @@ +# -*- encoding: utf-8 -*- +from NODE import * +from SOLVE import * +from EDGE import * +from WAYS import * + +N = Node() +E = Edge() +W = Ways() + +mode = tk.IntVar(value=1) +# 目前的操作状态: +# 1为节点操作 +# 2为链接操作 +# 3为路径操作 +# 默认为1 + + +RIGHT = -1 +B = tk.Button(frame, text="修改", command=lambda: N.node_set()) +B.place(x=180, y=10, width=50, height=30) + + +def left1(event): + # 查找鼠标左键按下时位置是否在某个节点内 + n = -1 + for node in d.Nodes: + if dir2([event.x, event.y], [node[3][0], node[3][1]]) < 20 * 20: + n = node[0] + + # n为点击的节点,若没有则为-1 + m = mode.get() # 查看现在操作类型 + if m == 1 and not n == -1: + # 节点操作 + + N.node_mark(n) + elif m == 2 and not n == -1: + # 链接操作 + if len(E.mark) == 0: + E.mark.append(n) + E.node_mark1(E.mark[0]) + elif len(E.mark) == 1: + E.mark.append(n) + E.node_mark1(E.mark[0]) + E.node_mark2(E.mark[1]) + elif not n == E.mark[1]: + n1 = E.mark[1] + E.mark.clear() + E.mark.append(n1) + E.mark.append(n) + E.node_mark1(E.mark[0]) + E.node_mark2(E.mark[1]) + # 路径操作 + elif m == 3 and not n == -1: + W.user_way_add(n) + # 自动判断操作 + elif m == 4 and not n == -1: + if len(solve.mark) == 0: + solve.mark.append(n) + solve.node_mark1(solve.mark[0]) + elif len(solve.mark) == 1: + solve.mark.append(n) + solve.node_mark1(solve.mark[0]) + solve.node_mark2(solve.mark[1]) + elif not n == solve.mark[1]: + n1 = solve.mark[1] + solve.mark.clear() + solve.mark.append(n1) + solve.mark.append(n) + solve.node_mark1(solve.mark[0]) + solve.node_mark2(solve.mark[1]) + + +def onRightButtonUp(event): + global RIGHT + # 查找鼠标右键按下时位置是否在某个节点内 + n = -1 + for node in d.Nodes: + if dir2([event.x, event.y], [node[3][0], node[3][1]]) < 20 * 20: + n = node[0] + if n == -1: + menu.post(event.x_root, event.y_root) + else: + RIGHT = n + menu_node.post(event.x_root, event.y_root) + + +# 右键菜单 +def m_node(): + mode.set(1) + W.clear() + N.node_mark_display() + + +def m_edge(): + mode.set(2) + W.clear() + E.edge_mark_display() + + +def m_ways(): + mode.set(3) + W.user_way_clear() + W.way_mark_display() + + +def m_info(): + d.edgeinfo ^= 1 + G.draw() + + +def m_solve(): + W.clear() + mode.set(4) + solve.Solve_display() + + +def graph_init(): + nodes = random.randint(4, 10) + N.node_init(nodes) + G.draw() + N.node_mark_display() + + +def sourc_set(num): + W.clear() + d.source = num + N.node_init(nodes) + G.draw() + + +def node_del(num): + N.node_mark(num) + N.node_del_exact() + + +def node_name(num): + N.node_mark(num) + N.node_rename() + + +def node_condition(num): + d.Nodes[num][4] ^= 1 + G.draw() + + +menu = tk.Menu(root, tearoff=0) +menu.add_command(label='节点操作', command=m_node) +menu.add_command(label='连接操作', command=m_edge) +menu.add_command(label='路径操作', command=m_ways) +menu.add_command(label='显示/隐藏链接信息', command=m_info) + +menu.add_command(label='自动判断相关', command=m_solve) +fmenu1 = Menu(menu, tearoff=False) +fmenu1.add_command(label='使用模拟数据', command=lambda: sourc_set(1)) +fmenu1.add_command(label='使用黑龙江省数据', command=lambda: sourc_set(2)) +fmenu1.add_command(label='使用辽宁省数据', command=lambda: sourc_set(3)) +menu.add_cascade(label="切换数据源", menu=fmenu1) + +menu_node = tk.Menu(root, tearoff=0) +menu_node.add_command(label='删除节点', command=lambda: node_del(RIGHT)) +menu_node.add_command(label='切换必经/非必经', command=lambda: node_condition(RIGHT)) +menu_node.add_command(label='重命名节点', command=lambda: node_name(RIGHT)) +# menu_node.add_command(label='显示/隐藏链接信息', command=m_info) + +cv.bind('', left1) +cv.bind('', onRightButtonUp) + + +# 释放右键时打开菜单 + +def auto_opera_mu(menu: tk.Menu): + """TSP问题自动生成与自动求解相关""" + menu_node = Menu(menu, tearoff=False) + menu_node.add_command(label="自动随机产生一个TSP问题", command=lambda: graph_init()) + menu_node.add_command(label="重新生成", command=lambda: N.node_refresh()) + menu_node.add_command(label="自动求解最优路径-遍历", command=lambda: solve.dfs_panel()) + menu_node.add_command(label="自动求解优化路径-贪心", command=lambda: solve.greedy_panel()) + menu_node.add_command(label="检查是否存在路径", command=lambda: solve.check()) + + # 在主目录菜单上新增"文件"选项,并通过menu参数与下拉菜单绑定 + menu.add_cascade(label="TSP问题自动生成与自动求解相关", menu=menu_node) + + +def node_opera_mu(menu: tk.Menu): + """节点操作""" + + # fmenu1 = Menu(menu, tearoff=False) + # for i in range(10): + # fmenu1.add_command(label='选择节点 ' + str(i + 1), command=lambda num=i: node_mark(num)) + + menu_node = Menu(menu, tearoff=False) + menu_node.add_command(label="添加一个节点", command=lambda: N.node_add()) + menu_node.add_command(label="删除一个节点", command=lambda: N.node_del()) + # menu_node.add_cascade(label="选择一个节点", menu=fmenu1) + menu_node.add_command(label="选择一个节点", command=lambda: N.node_mark_display()) + # menu_node.add_command(label="停止标记一个节点", command=lambda: node_mark_display1()) + # menu_node.add_command(label="设置节点标签", command=lambda:node_rename()) + + # 在主目录菜单上新增"文件"选项,并通过menu参数与下拉菜单绑定 + menu.add_cascade(label="节点操作", menu=menu_node) + + +def edge_opera_mu(menu: tk.Menu): + """连接操作""" + + # fmenu1 = Menu(menu, tearoff=False) + # for i in range(10): + # fmenu1.add_command(label='选择另一个节点 ' + str(i + 1), command=lambda num=i: node_mark2(num)) + # + menu_node = Menu(menu, tearoff=False) + # menu_node.add_cascade(label="选择另一个节点", menu=fmenu1) + + menu_node.add_command(label="选择一个连接", command=lambda: E.edge_mark_display()) + + # menu_node.add_command(label="建立一个连接",command=lambda :edge_add()) + menu_node.add_command(label="删除所有连接", command=lambda: E.edge_delall()) + menu_node.add_command(label="删除所有多余连接", command=lambda: E.newedge_del_all(1)) + # menu_node.add_command(label="设置连接标签", command=lambda: edge_rename()) + # 在主目录菜单上新增"文件"选项,并通过menu参数与下拉菜单绑定 + menu.add_cascade(label="连接操作", menu=menu_node) + + +def path_opera_mu(menu: tk.Menu): + """路径操作""" + menu_node = Menu(menu, tearoff=False) + menu_node.add_command(label="开始标记路径", command=lambda: W.way_mark_display()) + menu_node.add_command(label="撤销一步路径", command=lambda: W.user_way_del()) + menu_node.add_command(label="取消所有路径标记", command=lambda: W.user_way_clear()) + # 在主目录菜单上新增"文件"选项,并通过menu参数与下拉菜单绑定 + menu.add_cascade(label="路径操作", menu=menu_node, ) + + +auto_opera_mu(main_menu) +node_opera_mu(main_menu) +edge_opera_mu(main_menu) +path_opera_mu(main_menu) + + +def main(): + G = Graph() + G.draw() + sourc_set(2) + mainloop() + + +if __name__ == '__main__': + main() diff --git a/map.py b/map.py new file mode 100644 index 0000000..c13e2a1 --- /dev/null +++ b/map.py @@ -0,0 +1,41 @@ +# -*- encoding: utf-8 -*- +# 查询城市的经纬度并存入excel中 +# 本次整体的源代码 +AK = "9AfjsK2CXGuESwSb4sF3LsGhWh999Rdd" + +import pandas as pd +import requests +import json + +def getPosition(address): + url = r"http://api.map.baidu.com/place/v2/search?query={}®ion=全国&output=json&ak={}".format( + address, + AK # 这里是一开始截图用红色圈起来的部分,无需修改 + ) + res = requests.get(url) + json_data = json.loads(res.text) + + if json_data["status"] == 0: + lat = json_data["results"][0]["location"]["lat"] # 纬度 + lng = json_data["results"][0]["location"]["lng"] # 经度 + else: + print(json_data["message"]) + return "0,0", json_data["status"] + return lat,lng + + +if __name__ == "__main__": + res = [] + maps = ['哈尔滨市', '齐齐哈尔市', '鸡西市', '鹤岗市', '双鸭山市', '大庆市', '伊春市', '佳木斯市', '七台河市', '牡丹江市', '黑河市', '绥化市', '大兴安岭地区'] + + for i in range(len(maps)): + Name = maps[i] + P1 = getPosition(Name) + res.append([Name, P1[0], P1[1]]) + + pd.DataFrame(res).to_excel( + "data.xlsx", + header=["地点", "纬度", "经度"], + index=None, + encoding="utf-8" + )