题解:CF2110D Fewer Batteries

首先,看到这种和最小值有关的题,可以先想一下二分。

然后问题就转化为了有一个最大可行的携带数,看看能不能通过这个图,到达第 \(n\) 个点。

然后我们就不会了。这个携带电池不是一成不变的,所以我们生跑 bfs 是不对的。

我们考虑要达到一个什么状态,那显然是某个点到达最大的可能达到的携带电池数后再去更新其他的点。那就是拓扑排序了。

我们注意到,所有的边都是从小向大连边的,那我们直接从小向大跑就是一个拓扑序了,因为连向这个点的点都一定跑完了。

代码奉上。

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 2e5 + 5;

int n, m;
int b[N];
struct node {
    int v, w;
};
vector<node> edge[N];

int now[N], t[N];

queue<int> q;
bool check(int mid) {
    for(int i = 1;i <= n;i ++ ) now[i] = -1;
    now[1] = min(mid, b[1]);
    for(int u = 1;u <= n;u ++ ) {
        for(auto i : edge[u]) {
            int v = i.v;
            int w = i.w;
            if(now[u] >= w) {
                now[v] = max(now[v], min(mid, now[u] + b[v]));
            }
        }
    }
    return now[n] != -1;
}

void solve() {
    cin >> n >> m;
    int sum = 0;
    for(int i = 1;i <= n;i ++ ) {
        cin >> b[i];
        sum += b[i];
    }
    for(int i = 1;i <= m;i ++ ) {
        int u, v, w;
        cin >> u >> v >> w;
        edge[u].push_back({v, w});
    }

    int l = 0, r = sum;
    int ans = -1;
    while(l <= r) {
        int mid = l + r >> 1;
        if(check(mid)) {
            r = mid - 1;
            ans = mid;
        }
        else l = mid + 1;
    }
    cout << ans << "\n";

    for(int i = 1;i <= n;i ++ ) {
        edge[i].clear();
    }
}

signed main() {
    int T;
    cin >> T;
    while(T -- ) {
        solve();
    }
    return 0;
}
posted @ 2025-09-16 19:44  yanbinmu  阅读(6)  评论(0)    收藏  举报