8 グラフの探索
8.1 幅優先探索
\begin{algorithm} \caption{Breadth-First Search} \begin{algorithmic} \Require A graph $G = (V, E)$ and a source node $s$ \State Create a queue $Q$ \ForAll{$v \in V$} \State $\text{visited}[v] \gets \text{false}$ \EndFor \State $\text{visited}[s] \gets \text{true}$ \State $Q.\text{enqueue}(s)$ \While{$Q$ is not empty} \State $u \gets Q.\text{dequeue}()$ \ForAll{$v \in \text{Adj}(u)$} \If{not $\text{visited}[v]$} \State $\text{visited}[v] \gets \text{true}$ \State $Q.\text{enqueue}(v)$ \EndIf \EndFor \EndWhile \end{algorithmic} \end{algorithm}
8.1.1 Python Implementation
"""
Breadth-First Search for graph traversal.
graph = {
node: [neighbor1, neighbor2, ...],
...
}
"""
from collections import deque
def bfs(graph, start):
visited = {start}
queue = deque([start])
while queue:
node = queue.popleft()
print(node)
for neighbor in graph[node]:
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
if __name__ == "__main__":
graph = {
'A': ['B', 'C'],
'B': ['A', 'D', 'E'],
'C': ['A', 'F'],
'D': ['B'],
'E': ['B'],
'F': ['C']
}
bfs(graph, 'A')8.2 深さ優先探索
\begin{algorithm} \caption{Depth-First Search} \begin{algorithmic} \Require A graph $G = (V, E)$ and a source node $s$ \State Create a stack $S$ \ForAll{$v \in V$} \State $\text{visited}[v] \gets \text{false}$ \EndFor \State $\text{visited}[s] \gets \text{true}$ \State $S.\text{push}(s)$ \While{$S$ is not empty} \State $u \gets S.\text{pop}()$ \ForAll{$v \in \text{Adj}(u)$} \If{not $\text{visited}[v]$} \State $\text{visited}[v] \gets \text{true}$ \State $S.\text{push}(v)$ \EndIf \EndFor \EndWhile \end{algorithmic} \end{algorithm}
8.2.1 Python Implementation
"""
Depth-First Search for graph traversal.
graph = {
node: [neighbor1, neighbor2, ...],
...
}
"""
def dfs(graph, start):
visited = {start}
stack = [start]
while stack:
node = stack.pop()
print(node)
for neighbor in reversed(graph[node]):
if neighbor not in visited:
visited.add(neighbor)
stack.append(neighbor)
if __name__ == "__main__":
graph = {
'A': ['B', 'C'],
'B': ['D', 'E'],
'C': ['F', 'G'],
'D': ['H', 'I'],
'E': ['J', 'K'],
'F': ['L', 'M'],
'G': ['N', 'O'],
'H': [], 'I': [], 'J': [], 'K': [],
'L': [], 'M': [], 'N': [], 'O': []
}
dfs(graph, 'A')8.3 ダイクストラのアルゴリズム
\begin{algorithm} \caption{Dijkstra's Algorithm} \begin{algorithmic} \Require A graph $G = (V, E)$ with non-negative edge weights and a source node $s$ \State $W \gets \emptyset$ \ForAll{$v \in V$} \State $d[v] \gets \infty$ \EndFor \State $d[s] \gets 0$ \While{$W \neq V$} \State $u \gets \text{argmin}_{v \in V \setminus W} d[v]$ \State $W \gets W \cup \{u\}$ \ForAll{$v \in \text{Adj}(u)$} \State $d[v] \gets \min(d[v], d[u] + w(u, v))$ \EndFor \EndWhile \end{algorithmic} \end{algorithm}
"""
Dijkstra's Algorithm for shortest paths in a graph with non-negative edge weights.
graph = {
node: [(neighbor, weight), ...],
...
}
"""
def dijkstra(graph, source):
dist = {node: float("inf") for node in graph}
dist[source] = 0
W = set()
while W != set(graph):
# Find the node with the smallest distance
x = min(
(node for node in graph if node not in W),
key=lambda node: dist[node]
)
W.add(x)
for v, weight in graph[x]:
if v not in W:
dist[v] = min(
dist[v],
dist[x] + weight)
return dist
if __name__ == "__main__":
graph = {
0: [(1, 2), (2, 1)],
1: [(2, 3), (3, 3)],
2: [(4, 1)],
3: [(5, 2)],
4: [(3, 2), (5, 5)],
5: [],
}
distances = dijkstra(graph, 0)
print(distances)