洛谷P1396 营救 题解

本题做法

  • 二分答案+BFS。

思路

对于输入的数据,使用4个数组\(head,tail,value,next\)记录每个点的第一条边、每条边的结尾、每条边的拥挤值以及每条边的下一条边。

随后使用二分答案法二分所求的答案,使用\(check\)函数检测是否可行。

\(check\)函数:从\(s\)点开始BFS,若当前边的\(value\)小于等于\(x\),则将当前边的\(tail\)加入队列,继续BFS。最后,判断是否走过\(t\)点,若走过,则返回true;否则返回false。

代码

#include <bits/stdc++.h>
#define endl '\n'
#define ll long long

using namespace std;

const int INF = 0x3f3f3f3f;
const double EPS = 1e-8;
const int N = 2e5 + 5;

int n, m, s, t, u, v, w, mxw = -1;
int value[N], /*表示第i条边的拥挤度*/ head[N], /*表示第i个点的第一条边*/
    tail[N], /*表示第i条边的*/ nxt[N];         /*表示第i条边的下一条边*/
bool vis[N];

bool check(int x) {
    memset(vis, 0, sizeof(vis));
    queue<int> q;
    vis[s] = 1;
    q.push(s);
    while (!q.empty()) {
        int stt = head[q.front()];
        q.pop();
        while (stt) {
            if (value[stt] <= x && !vis[tail[stt]]) {
                q.push(tail[stt]);
                vis[tail[stt]] = 1;
            }
            stt = nxt[stt];
        }
    }
    return vis[t];
}

int main() {
    cin >> n >> m >> s >> t;
    for (int i = 1; i <= m; i++) {
        cin >> u >> v >> w;
        // 从u到v的边
        value[2 * i] = w;
        tail[2 * i] = v;
        nxt[2 * i] = head[u];
        head[u] = 2 * i;
        // 从v到u的边
        value[2 * i + 1] = w;
        tail[2 * i + 1] = u;
        nxt[2 * i + 1] = head[v];
        head[v] = 2 * i + 1;
        mxw = max(mxw, w);
    }
    if (s == t) {
        cout << 0 << endl;
        return 0;
    }
    int l = 0, r = mxw + 1;
    while (l + 1 < r) {
        int mid = l + (r - l) / 2;
        if (check(mid))
            r = mid;
        else
            l = mid;
    }
    cout << r << endl;
    return 0;
}

posted @ 2025-03-01 22:10  2789617221guo  阅读(30)  评论(0)    收藏  举报