1. 程式人生 > >[Codeforces 346D] Robot Control(01BFS)

[Codeforces 346D] Robot Control(01BFS)

main 一道 pop || ado 代碼 ret 就是 va_arg

題意

有一個 \(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)