# 0-1 BFS 0-1 BFS 是一個找最短路徑的演算法,他要處理的問題很簡單: 「給定一張有向圖,與一個起點 $s$,每條邊的邊權只會是 $0$ 或 $1$,請求出單源最短路徑」 ## 想法 想當然,我們可以直接使用 [Dijkstra 演算法](https://hackmd.io/@ShanC/Dijkstra) 求出答案,但是這樣時間就會多出一個 $\log$,很不划算 我們可以重新省視一下題目,通常最短路徑中我們會想要用 `priority_queue` 是因為每次取出來會是最小。但我們現在的邊權僅有 $0$ 或 $1$ 而已,只要碰到 $1$ 的那條邊,權重和就會變大,因此我們不需要像 Dijkstra 一樣維護「加到目前的權重和」,直接維護「眼前這條邊的權重」即可。所以可以考慮利用一個容器,頭放權重 $+0$ 的點,尾忘權重 $+1$ 的點,並且每次取頭的元素就好 ## 演算法 實作上我們可以使用 `deque` 來當作這個容器。老樣子 `dis[]` 是距離陣列,`g[]` 是圖 ```cpp= vector<int> bfs01(int s) { vector<int> dis(n, INF); dis[s] = 0; deque<int> q; q.push_front(s); while (!q.empty()) { int v = q.front(); q.pop_front(); for (auto edge : g[v]) { int u = edge.first, w = edge.second; if (dis[v] + w < dis[u]) { dis[u] = dis[v] + w; if (w) q.push_back(u); // w==1 放尾 else q.push_front(u); // w==0 放頭 } } } return dis; } ``` ## 時間複雜度 設 $n$ 為點數、$m$ 為邊數 時間複雜度: $O(n+m)$ ## 備註 有一個拓展的演算法叫 Dial's algorithm,他的想法很簡單,只要邊權 $\le k$,那就直接開 $k$ 個 queue。由於我打競程到現在還沒遇過,所以就不寫囉 ## 題目練習 [codeforces 1063B - Labyrinth](https://codeforces.com/contest/1063/problem/B) [AtCoder Beginner Contest 246E - Bishop 2](https://atcoder.jp/contests/abc246/tasks/abc246_e) [AtCoder アルゴリズムと数学 演習問題集 048 - Small Multiple](https://atcoder.jp/contests/math-and-algorithm/tasks/arc084_b) (這題其實也可以 Dijkstra,取決於你怎麼建圖) ---- ## 參考資料 [CP-algorithms - 0-1 BFS](https://cp-algorithms.com/graph/01_bfs.html) [海大競程 2025 I2CP 講義 - shortest path](https://hackmd.io/@LeeShoWhaodian/HyT4ib5qJg) ---- > [ShanC 程式競賽筆記](https://hackmd.io/@ShanC/B1ouGxqcC) > 作者: ShanC > 更新: 2026/1/29