[Codeforces 346D] Robot Control(01BFS)
題意
有一個 \(N\) 個點, \(M\) 條邊的有向圖, 初始有一個機器人在 \(1\) 號點. 每個時刻, 這個機器人會隨機選擇一條從該點出發地邊並通過.當機器人到達點 \(N\) 時, 它就會自動關閉.
然而這個機器人如果在某個時刻到達自己曾經到過的點的話, 它就會爆炸. 因此, 你決定對機器人實施一些命令, 讓它在某些時候按照規定的邊走, 而非隨機選擇.
問對機器人最少使用多少條命令可以讓它安全到達點 \(N\) .
\(N, M \le 10^6\)
題解
十分巧妙的一道好題~
首先可以無視掉 “不能到達曾經到過的點” 的限制, 因為最優答案一定不會存在這種情況.
因為到達曾經到過的點,你至少要付出更多代價才能回到這個點,所以絕對不優。
然後我們就可以考慮一個 \(dp\) 了,令 \(dp_u\) 為 \(u\) 走到 \(T\) 需要的最少命令。
那麽顯然有一個轉移:
\[
dp_v=\min_{(u, v)} \{\min\{dp_v\}+1,\max\{dp_v\}\}
\]
這個意義是很明顯的,就不解釋了。
這個本質上是個 \(0 / 1\) BFS 問題,用個雙端隊列維護就行了,\(0\) 加到隊首, \(1\) 加到隊尾就行了。
具體實現的時候,我們只有在第一次到達這個點的時候會更新 \(\min\{dp_v\}+1\) ,因為是 BFS 最早到的肯定是距離較小的點。
也就是隊列中的點 \(dis\) 單調不下降。
然後最後一次到達這個點才會更新 \(\max\{dp_v\}\) ,同樣這是 BFS 最晚到的點。
每個點我們只會訪問一次,所以最後一次到達就是它入度減少到 \(0\) 的時候。
代碼
記得要把邊反向,以及入度也要反向。
#include <bits/stdc++.h> #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i) #define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i) #define Set(a, v) memset(a, v, sizeof(a)) #define Cpy(a, b) memcpy(a, b, sizeof(a)) #define debug(x) cout << #x << ": " << x << endl #define DEBUG(...) fprintf(stderr, __VA_ARGS__) using namespace std; inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;} inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;} inline int read() { int x = 0, fh = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1; for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48); return x * fh; } void File() { #ifdef zjp_shadow freopen ("D.in", "r", stdin); freopen ("D.out", "w", stdout); #endif } const int N = 1e6 + 1e3; int n, m, deg[N], dp[N]; vector<int> G[N]; int S, T; bitset<N> vis; void Bfs() { Set(dp, -1); deque<int> Q; Q.push_front(T); dp[T] = 0; while (!Q.empty()) { int u = Q.front(); Q.pop_front(); if (u == S) return ; if (vis[u]) continue ; vis[u] = true; for (int v : G[u]) if (!-- deg[v]) { if (!~dp[v] || dp[u] < dp[v]) dp[v] = dp[u], Q.push_front(v); } else if (!~dp[v]) dp[v] = dp[u] + 1, Q.push_back(v); } } int main () { File(); n = read(); m = read(); For (i, 1, m) { int u = read(), v = read(); G[v].push_back(u); ++ deg[u]; } S = read(), T = read(); Bfs(); printf ("%d\n", dp[S]); return 0; }
[Codeforces 346D] Robot Control(01BFS)