8  最短路問題

有向グラフ G = (V, E) を考える.各辺 (v, u) \in E に非負の重み w(v, u) が与えられているとする.このとき,点 s \in V から点 t \in V への最短路(shortest path)とは,s から t へのパスのうち,重みの和が最小となるパスである. 最短路問題とは,s から t への最短路を求める問題である.

例 8.1 次の図は,最短路問題の例を示している.

コード
import matplotlib.pyplot as plt
import networkx as nx
import numpy as np

# グラフの作成(頂点を番号で定義)
G = nx.DiGraph()
edges = [
    ("s", "v1", 5),
    ("s", "v2", 3),
    ("v1", "v3", 17),
    ("v2", "v3", 1),
    ("v2", "v4", 3),
    ("v3", "t", 4),
    ("v4", "t", 2),
]
G.add_weighted_edges_from(edges)

labels = {
    node: (rf"$v_{node[1:]}$" if node.startswith("v") else rf"${node}$")
    for node in G.nodes()
}

for layer, nodes in enumerate(nx.topological_generations(G)):
    for node in nodes:
        G.nodes[node]["layer"] = layer

# pos = nx.multipartite_layout(G, subset_key="layer")
pos = {
    "s": (0, 0),
    "v1": (1, 1),
    "v2": (1, -1),
    "v3": (2, 1),
    "v4": (2, -1),
    "t": (3, 0),
}

label_pos = {}
for k, (x, y) in pos.items():
    r = np.sqrt(x**2 + y**2) if np.sqrt(x**2 + y**2) > 0 else 1
    scale = 1.1
    label_pos[k] = (x * scale, y * scale)

label_pos["s"] = (label_pos["s"][0] - 0.15, label_pos["s"][1])
label_pos["t"] = (label_pos["t"][0] - 0.15, label_pos["t"][1])

# Plotting
nx.draw_networkx(
    G,
    pos=pos,
    with_labels=False,
    node_color="white",
    node_size=50,
    edgecolors="#16212d",
)
nx.draw_networkx_labels(G, label_pos, labels, font_size=12)
nx.draw_networkx_edge_labels(
    G,
    pos,
    edge_labels={(u, v): d["weight"] for u, v, d in G.edges(data=True)},
    font_color="#16212d",
    font_size=12,
)
plt.axis("off")
plt.show()