洛谷题单指南-最短路-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;
}
浙公网安备 33010602011771号