E - Charles in Charge

本质上是最短路+二分
本题要求是再求最短路的基础上限制边长,边长最长是 \(dis*(1 + x / 100)\),在求出限制边长后,可以通过二分找出答案
在二分中,大于限制边长的不予考虑

#include <cstring>
#include <iostream>
#include <queue>

using namespace std;
const int N = 1e5 + 10, M = 1e6 + 10;
typedef long long ll;
typedef pair<ll, ll> PII;
int h[N], e[M], w[M], ne[M], idx;
int n, m, x;
bool st[N];
ll dis[N];

const ll INF = 1e18;//最大值
inline void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
ll disjktra(ll l)//限制边长
{
    for (int i = 0; i <= n; i++) {
        dis[i] = INF;
        st[i] = 0;
    }
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({ 0, 1 });
    dis[1] = 0;
    while (heap.size()) {
        PII r = heap.top();
        heap.pop();

        ll dist = r.first;
        if (st[r.second])
            continue;
        st[r.second] = 1;
        for (int i = h[r.second]; i != -1; i = ne[i]) {
            int j = e[i];
            if (w[i] <= l && dis[j] > dist + w[i]) {
                dis[j] = dist + w[i];

                heap.push({ dis[j], j });
            }
        }
    }
    return dis[n];
}

int main()
{
    cin.tie(0)->sync_with_stdio(0);
    cin >> n >> m >> x;
    memset(h, -1, sizeof h);
    ll v = -1;
    while (m--) {
        ll a, b, c;
        cin >> a >> b >> c;
        v = max(v, c);
        add(a, b, c);
        add(b, a, c);
    }
    ll u = disjktra(INF);
    double sum = u * 1.0 * (x * 1.0 / 100 + 1) * 1.0;
    ll l = 0, r = v;
    while (l < r) {
        ll mid = l + (r - l) / 2;
        if (disjktra(mid) * 1.0 == sum) {
            {
                cout << mid << endl;
                return 0;
            }
        } else if (disjktra(mid) * 1.0 < sum)
            r = mid;
        else if (disjktra(mid) * 1.0 > sum)
            l = mid + 1;
    }
    cout << l << endl;
    return 0;
}
posted @ 2022-07-12 11:10  Flying_bullet  阅读(18)  评论(0编辑  收藏  举报