def initialize(dag: DirectGraph, s: Vertex, t: Vertex): """ 做搜索前 forward backward 的初始化 :return: """ Sf = {s} Sb = {t} Qf = set() Qb = set() df = {s: 0} db = {t: 0} paif = {s: None} paib = {t: None} for u in dag.vertexes: if u != s: Qf.add(u) w = dag.get_edge_weight(s, u) df[u] = w if w < sys.maxsize: paif[u] = s else: paif[u] = None if u != t: Qb.add(u) w = dag.get_edge_weight(u, t) db[u] = w if w < sys.maxsize: paib[u] = t else: paib[u] = None return Sf, Sb, Qf, Qb, df, db, paif, paib
def dijkstra(dg: DirectGraph, s: Vertex): """ 使用 Dijkstra 遍历有向无环图,假设该图为有向无环图 DAG,以下代码不做判断 :param dg: course13.graph.DirectGraph :param s: 寻找DAG中所有顶点到 s 的最短路径 S.P :return: """ if not dg.has_vertex(s): print(dg) raise Exception("顶点: {} 不在 DAG 中") # S 为已经找到最短路径的顶点 # Q 为尚未找到最短路径的顶点 # d 为对应目前迭代中该顶点到 s 的距离 # pai 用于记录在最短路径中,该顶点的上一个顶点 S, Q, d, pai = initialize(dg, s) while Q: # extract-min from Q v, minimize = extract_min(Q, d) if v is not None: S.add(v) Q.remove(v) relax(dg, d, pai, v) else: # 所有可以被 S 达到的顶点都已经被遍历,剩下的顶点无法从 s 到达 break return d, pai
def dijkstra_single_source_single_target(dg: DirectGraph, s: Vertex, t: Vertex): """ 使用 Dijkstra 遍历有向无环图,假设该图为有向无环图 DAG,以下代码不做判断 寻找 DAG 中 s-->t 的最短路径 :param dg: course13.graph.DirectGraph :param s: 寻找DAG中所有顶点到 s 的最短路径 S.P :param t: 目标顶点 :return: """ if not dg.has_vertex(s): print(dg) raise Exception("顶点: {} 不在 DAG 中") # S 为已经找到最短路径的顶点 # Q 为尚未找到最短路径的顶点 # d 为对应目前迭代中该顶点到 s 的距离 # pai 用于记录在最短路径中,该顶点的上一个顶点 S, Q, d, pai = initialize(dg, s) while Q: # extract-min from Q v, minimize = extract_min(Q, d) # 如果 v == t 那么可以停止搜索,已经找到了目标 s-->t 最短路径 if v == t: S.add(v) Q.remove(v) break if v is not None: S.add(v) Q.remove(v) relax(dg, d, pai, v) else: # 所有可以被 S 达到的顶点都已经被遍历,剩下的顶点无法从 s 到达 # 有可能 s-x->t 不存在这样的路径,也就是 d[t] = sys.maxsize break return d, pai
def initialize(dag: DirectGraph): """ 对进行 Floyd 算法求解之前先进行数据的初始化 :return: """ vexnum = dag.get_vertex_num() # Graph 中顶点以 set() 集和存储,这里我们需要将其转化为 list,方便使用下标 index 访问,list 中保存的只是引用,根本上还是 Graph 中 set 的顶点 vexes = list( dag.vertexes) # 由于是从 set 转化为 list,所以即使是相同的顶点,生成的 list 每次顶点顺序也可能不一样 # 用于记录最短路径的关系的三维数组 p p = [[[False for _ in range(vexnum)] for j in range(vexnum)] for i in range(vexnum)] # 生成用于记录图中每两个顶点之间的最短路径的二维数组 d[i][j] 代表 vi-->vj 的距离 d = [[ dag.get_edge_weight(vexes[i], vexes[j]) if i != j else 0 for j in range(vexnum) ] for i in range(vexnum)] for i in range(vexnum): for j in range(vexnum): if d[i][j] < sys.maxsize: p[i][j][i], p[i][j][j] = True, True return d, p, vexes, vexnum
def initialize(dg: DirectGraph, s: Vertex): """ 对数据进行初始化,这里仅仅初始化 distance dict, pai 记录最路径中访问的上一个顶点 :param dg: :return: """ d = {s: 0} pai = {s: None} for v in dg.vertexes: pai[v] = None if v != s: d[v] = dg.get_edge_weight(s, v) # 使用 sys.maxsize 代表两者之间没有任何关联 if d[v] < sys.maxsize: pai[v] = s return d, pai
def topology(dag: DirectGraph): """ 求 DAG 的拓扑结构 :param dag: :return: """ indegree = initialize(dag) # 顶点加入拓扑结构的顺序 order = [] vexnum = dag.get_vertex_num() while len(order) < vexnum: for v, c in indegree.items(): if c == 0: order.append(v) # 更新 -1 代表已经加入了拓扑结果 indegree[v] = -1 update(dag, v, indegree) break else: # 图中有环,无法计算该图的拓扑结构 raise CycleException('图中有环,无法计算该图的拓扑结构') return order
def initialize(dg: DirectGraph, s): """ 在进行 Dijkstra 算法前先进行初始化数据 :param dg: :param s: :return: """ # 所有已经找到了最短路径的顶点集和 S = {s} # 所有还没有找到最短路径的顶点集和 Q = set() d = {s: 0} pai = {s: None} # 将所有非 s 顶点加入到 Q 中 for v in dg.vertexes: pai[v] = None if v != s: Q.add(v) d[v] = dg.get_edge_weight(s, v) if d[v] < sys.maxsize: pai[v] = s return S, Q, d, pai
def bellman_ford(dg: DirectGraph, s: Vertex): """ 使用 Bellman-Ford 寻找图中的最短路径 :param dg: 有向图,其中图中可以存在 negative-weight cycle,Bellman-Ford 算法可以发现 negative-weight cycle :param s: 源点 s :return: """ # d 用来记录每个顶点距离 s 的最短路径 # pai 用于记录每个顶点在最短路径中访问的上一个顶点 d, pai = initialize(dg, s) vertex_num = dg.get_vertex_num() # 进行 |V| - 1 次循环 for _ in range(1, vertex_num): # 这里从每个顶点开始遍历每一条边 for u, l in dg.edges.items(): for v, w in l: relax(u, v, w, d, pai) try: check(dg, d) except NegativeCycleException: print("图中存在 negative-weight cycle") else: print("图中不存在 negative-weight cycle") return d, pai
def test_dijkstra(): dg = DirectGraph() a = Vertex('a') b = Vertex('b') c = Vertex('c') d = Vertex('d') e = Vertex('e') f = Vertex('f') g = Vertex('g') dg.add_vertex(a) dg.add_vertex(b) dg.add_vertex(c) dg.add_vertex(d) dg.add_vertex(e) dg.add_vertex(f) dg.add_vertex(g) dg.add_edge(a, b, 2) dg.add_edge(d, a, 3) dg.add_edge(b, c, 3) dg.add_edge(c, d, 5) dg.add_edge(c, e, 6) dg.add_edge(c, f, 4) dg.add_edge(g, e, 1) dg.add_edge(f, g, 2) dg.add_edge(b, e, 2) dg.add_edge(e, g, 3) d, pai = dijkstra(dg, a) print(d, pai)
def test(): # 以下图中有两条关键路径 # 1: a-->b-->e-->g-->h # 2: a-->b-->e-->f-->h dag = DirectGraph() a = Vertex('a') b = Vertex('b') c = Vertex('c') d = Vertex('d') e = Vertex('e') f = Vertex('f') g = Vertex('g') h = Vertex('h') i = Vertex('i') dag.add_vertex(a) dag.add_vertex(b) dag.add_vertex(c) dag.add_vertex(d) dag.add_vertex(e) dag.add_vertex(f) dag.add_vertex(g) dag.add_vertex(h) dag.add_vertex(i) dag.add_edge(a, b, 6) dag.add_edge(a, c, 4) dag.add_edge(a, d, 5) dag.add_edge(b, e, 1) dag.add_edge(c, e, 1) dag.add_edge(d, i, 2) dag.add_edge(e, f, 9) dag.add_edge(e, g, 7) dag.add_edge(f, h, 2) dag.add_edge(g, h, 4) dag.add_edge(i, g, 4) key_path = find_key_path(dag) print(key_path)
def test_cycle(): dag = DirectGraph() a = Vertex('a') b = Vertex('b') c = Vertex('c') d = Vertex('d') e = Vertex('e') f = Vertex('f') g = Vertex('g') h = Vertex('h') dag.add_vertex(a) dag.add_vertex(b) dag.add_vertex(c) dag.add_vertex(d) dag.add_vertex(e) dag.add_vertex(f) dag.add_vertex(g) dag.add_vertex(h) dag.add_edge(a, b, 2) dag.add_edge(d, a, 3) dag.add_edge(b, c, 3) dag.add_edge(c, d, 5) dag.add_edge(c, e, 6) dag.add_edge(c, f, 4) dag.add_edge(g, e, 1) dag.add_edge(f, g, 2) dag.add_edge(b, e, 2) dag.add_edge(e, g, 3) dag.add_edge(g, c, 3) order = topology(dag) print(order)
def test_topology(): dag = DirectGraph() a = Vertex('a') b = Vertex('b') c = Vertex('c') d = Vertex('d') e = Vertex('e') f = Vertex('f') g = Vertex('g') dag.add_vertex(a) dag.add_vertex(b) dag.add_vertex(c) dag.add_vertex(d) dag.add_vertex(e) dag.add_vertex(f) dag.add_vertex(g) dag.add_edge(a, b) dag.add_edge(b, c) dag.add_edge(c, d) dag.add_edge(e, c) dag.add_edge(c, g) dag.add_edge(c, f) dag.add_edge(d, f) order = topology(dag) print(order)
def test_dijkstra_single_source_single_target(): dg = DirectGraph() a = Vertex('a') b = Vertex('b') c = Vertex('c') d = Vertex('d') e = Vertex('e') f = Vertex('f') g = Vertex('g') dg.add_vertex(a) dg.add_vertex(b) dg.add_vertex(c) dg.add_vertex(d) dg.add_vertex(e) dg.add_vertex(f) dg.add_vertex(g) dg.add_edge(a, b, 2) dg.add_edge(d, a, 3) dg.add_edge(b, c, 3) dg.add_edge(c, d, 5) dg.add_edge(c, e, 6) dg.add_edge(c, f, 4) dg.add_edge(g, e, 1) dg.add_edge(f, g, 2) dg.add_edge(b, e, 2) dg.add_edge(e, g, 3) s, t = a, g d, pai = dijkstra_single_source_single_target(dg, s, t) print(d, pai) print('=======') print_shortest_path(pai, s, t)
def test_floyd(): dag = DirectGraph() a = Vertex('a') b = Vertex('b') c = Vertex('c') d = Vertex('d') e = Vertex('e') f = Vertex('f') g = Vertex('g') h = Vertex('h') dag.add_vertex(a) dag.add_vertex(b) dag.add_vertex(c) dag.add_vertex(d) dag.add_vertex(e) dag.add_vertex(f) dag.add_vertex(g) # dag.add_vertex(h) dag.add_edge(a, b, 2) dag.add_edge(d, a, 3) dag.add_edge(b, c, 3) dag.add_edge(c, d, 5) dag.add_edge(c, e, 6) dag.add_edge(c, f, 4) dag.add_edge(g, e, 1) dag.add_edge(f, g, 2) dag.add_edge(b, e, 2) dag.add_edge(e, g, 3) dag.add_edge(g, c, 3) d, p, vexes = floyd(dag) pprint.pprint(vexes) pprint.pprint(d) pprint.pprint(p)
def test(): dag = DirectGraph() a = Vertex('a') b = Vertex('b') c = Vertex('c') d = Vertex('d') e = Vertex('e') f = Vertex('f') g = Vertex('g') h = Vertex('h') dag.add_vertex(a) dag.add_vertex(b) dag.add_vertex(c) dag.add_vertex(d) dag.add_vertex(e) dag.add_vertex(f) dag.add_vertex(g) dag.add_vertex(h) dag.add_edge(a, b, 2) dag.add_edge(d, a, 3) dag.add_edge(b, c, 3) dag.add_edge(c, d, 5) dag.add_edge(c, e, 6) dag.add_edge(c, f, 4) dag.add_edge(g, e, 1) dag.add_edge(f, g, 2) dag.add_edge(b, e, 2) dag.add_edge(e, g, 3) dag.add_edge(g, c, 3) try: df, db, paif, paib, n = bi_dijkstra(dag, g, a) print('df: ', df) print('db: ', db) print('paif: ', paif) print('paib ', paib) print_shortest_path(paif, paib, n) except NoPathException as e: print(e)