Skip to content

Commit 04288b1

Browse files
committed
feat: python impl for 0-1 BFS
1 parent edea689 commit 04288b1

File tree

1 file changed

+69
-39
lines changed

1 file changed

+69
-39
lines changed

src/graph/01_bfs.md

Lines changed: 69 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ tags:
77

88
It is well-known, that you can find the shortest paths between a single source and all other vertices in $O(|E|)$ using [Breadth First Search](breadth-first-search.md) in an **unweighted graph**, i.e. the distance is the minimal number of edges that you need to traverse from the source to another vertex.
99
We can interpret such a graph also as a weighted graph, where every edge has the weight $1$.
10-
If not all edges in graph have the same weight, that we need a more general algorithm, like [Dijkstra](dijkstra.md) which runs in $O(|V|^2 + |E|)$ or $O(|E| \log |V|)$ time.
10+
If not all edges in graph have the same weight, then we need a more general algorithm, like [Dijkstra](dijkstra.md) which runs in $O(|V|^2 + |E|)$ or $O(|E| \log |V|)$ time.
1111

1212
However if the weights are more constrained, we can often do better.
1313
In this article we demonstrate how we can use BFS to solve the SSSP (single-source shortest path) problem in $O(|E|)$, if the weight of each edge is either $0$ or $1$.
@@ -17,27 +17,41 @@ In this article we demonstrate how we can use BFS to solve the SSSP (single-sour
1717
We can develop the algorithm by closely studying Dijkstra's algorithm and thinking about the consequences that our special graph implies.
1818
The general form of Dijkstra's algorithm is (here a `set` is used for the priority queue):
1919

20-
```cpp
21-
d.assign(n, INF);
22-
d[s] = 0;
23-
set<pair<int, int>> q;
24-
q.insert({0, s});
25-
while (!q.empty()) {
26-
int v = q.begin()->second;
27-
q.erase(q.begin());
28-
29-
for (auto edge : adj[v]) {
30-
int u = edge.first;
31-
int w = edge.second;
32-
33-
if (d[v] + w < d[u]) {
34-
q.erase({d[u], u});
35-
d[u] = d[v] + w;
36-
q.insert({d[u], u});
20+
=== "C++"
21+
```cpp
22+
d.assign(n, INF);
23+
d[s] = 0;
24+
set<pair<int, int>> q;
25+
q.insert({0, s});
26+
while (!q.empty()) {
27+
int v = q.begin()->second;
28+
q.erase(q.begin());
29+
30+
for (auto edge : adj[v]) {
31+
int u = edge.first;
32+
int w = edge.second;
33+
34+
if (d[v] + w < d[u]) {
35+
q.erase({d[u], u});
36+
d[u] = d[v] + w;
37+
q.insert({d[u], u});
38+
}
3739
}
3840
}
39-
}
40-
```
41+
```
42+
=== "Python"
43+
```py
44+
d = [float("inf")] * n
45+
d[s] = 0
46+
q = {(0, s)}
47+
while q:
48+
_, v = q.pop()
49+
for u, w in adj[v]:
50+
if d[v] + w < d[u]:
51+
q.discard((d[u], u))
52+
d[u] = d[v] + w
53+
q.add((d[u], u))
54+
```
4155

4256
We can notice that the difference between the distances between the source `s` and two other vertices in the queue differs by at most one.
4357
Especially, we know that $d[v] \le d[u] \le d[v] + 1$ for each $u \in Q$.
@@ -53,27 +67,43 @@ This structure is so simple, that we don't need an actual priority queue, i.e. u
5367
We can simply use a normal queue, and append new vertices at the beginning if the corresponding edge has weight $0$, i.e. if $d[u] = d[v]$, or at the end if the edge has weight $1$, i.e. if $d[u] = d[v] + 1$.
5468
This way the queue still remains sorted at all time.
5569

56-
```cpp
57-
vector<int> d(n, INF);
58-
d[s] = 0;
59-
deque<int> q;
60-
q.push_front(s);
61-
while (!q.empty()) {
62-
int v = q.front();
63-
q.pop_front();
64-
for (auto edge : adj[v]) {
65-
int u = edge.first;
66-
int w = edge.second;
67-
if (d[v] + w < d[u]) {
68-
d[u] = d[v] + w;
69-
if (w == 1)
70-
q.push_back(u);
71-
else
72-
q.push_front(u);
70+
=== "C++"
71+
```cpp
72+
vector<int> d(n, INF);
73+
d[s] = 0;
74+
deque<int> q;
75+
q.push_front(s);
76+
while (!q.empty()) {
77+
int v = q.front();
78+
q.pop_front();
79+
for (auto edge : adj[v]) {
80+
int u = edge.first;
81+
int w = edge.second;
82+
if (d[v] + w < d[u]) {
83+
d[u] = d[v] + w;
84+
if (w == 1)
85+
q.push_back(u);
86+
else
87+
q.push_front(u);
88+
}
7389
}
7490
}
75-
}
76-
```
91+
```
92+
=== "Python"
93+
```py
94+
d = [float("inf")] * n
95+
d[s] = 0
96+
q = deque([s])
97+
while q:
98+
v = q.popleft()
99+
for u, w in adj[v]:
100+
if d[v] + w < d[u]:
101+
d[u] = d[v] + w
102+
if w == 1:
103+
q.append(u)
104+
else:
105+
q.appendleft(u)
106+
```
77107

78108
## Dial's algorithm
79109

0 commit comments

Comments
 (0)