洛谷题单指南-最短路-P1462 通往奥格瑞玛的道路

原题链接:https://www.luogu.com.cn/problem/P1462

题意解读:有n个点,m条边,每个点有过路费属性,每条边有减血量属性,有初始血量b,要求所有从起点到终点的路径方案中,血量没有降为负数时,某一条路径中的点的最大过路费的最小值。

解题思路:

要求最大过路费的最小值,猜测可以二分,来分析一下能否二分答案来划分条件:

设每次二分一个可能的最大过路费mid,

在check函数中,应该针对所有过路费不超过mid的点,从起点跑一遍最短路,可以是SPFA或者Dijikstra

如果终点到起点的最短路<=b,说明可以从起点走到终点,mid是一个符合要求的解,可以进一步缩小查询范围

否则可以扩大mid的查询范围。

二分的思路呼之欲出,这里最短路采用比较好写的SPFA。

需要注意:起点也要判断过路费是否不超过mid。

100分代码:

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

const int N = 10005, M = 100005;
int f[N]; //每个城市的过路费
int h[N], e[M], w[M], ne[M], idx;
long long dist[N]; //距离起点总共损失的血量
bool vis[N];
int n, m, b;

void add(int a, int b, int c)
{
    e[++idx] = b;
    w[idx] = c;
    ne[idx] = h[a];
    h[a] = idx;
}

//用spfa求所有过路费不超过x的节点中,从1-n的最短路,看是否能确保血量不为负
bool check(int x)
{
    memset(dist, 0x3f, sizeof(dist));
    if(f[1] > x) return false; //如果起点的过路费超过x,则本次二分结果不满足
    dist[1] = 0;
    queue<int> q;
    q.push(1);
    while(q.size())
    {
        int u = q.front(); q.pop();
        vis[u] = false;

        for(int i = h[u]; ~i; i = ne[i])
        {
            int v = e[i];
            if(f[v] > x) continue;
            if(dist[v] > dist[u] + w[i])
            {
                dist[v] = dist[u] + w[i];
                if(!vis[v])
                {
                    q.push(v);
                    vis[v] = true;
                }
            }
        }
    }
    return dist[n] <= b;
}

int main()
{
    memset(h, -1, sizeof(h));
    cin >> n >> m >> b;
    for(int i = 1; i <= n; i++) cin >> f[i];
    while(m--)
    {
        int u, v, w;
        cin >> u >> v >> w;
        add(u, v, w);
        add(v, u, w);
    }

    //对结果进行二分答案
    int l = 0, r = 1e9 + 1;
    while(l < r) 
    {
        int mid = l + r >> 1;
        if(check(mid)) r = mid;
        else l = mid + 1;
    }
    if(r == 1e9 + 1) cout << "AFK";
    else cout << r;

    return 0;
}

 

posted @ 2025-04-10 16:19  hackerchef  阅读(34)  评论(0)    收藏  举报