P1462 通往奥格瑞玛的道路
题意
现在有n个城市,编号为1-n,起点为1,终点为n,有m条双向的公路,你现在有b单位的血量,每一条路会损失c[i]单位的血量,然后没经过一个城市会花费f[i]元,现在让你求:从1-n这条路径上的最大花费的最小值。
思路
最短路+二分
二分:二分花费,假如我们现在的花费为x,当x的值越大,那么我们可以走到的地方越远,那么我们可以知道,花费对于我们所走的路程是存在单调递增的,所以可以用二分来寻找我们所要找的最大花费的最小值。
最短路:其实这里也不能说是最短路(个人感觉),因为我们只需要在血量充足的情况下从起点走到终点, 这条路径不一定是最优的(不需要在意花费),也许某一条不是最优的路径中的最大花费的值是最小的。但是题目中说了不希望花很多钱
,那么就是找最短路。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e4 + 10, M = 1e5 + 10, inf = 1000000005;
int n, m, b;
int f[N];
int dis[N], st[N];
int e[M], w[M], ne[M], h[M], idx;
void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++; }
bool spfa(int x)
{
memset(dis, inf, sizeof dis);
queue<int> q;
q.push(1);
st[1] = 1;
dis[1] = 0;
while (!q.empty())
{
int u = q.front(); q.pop();
st[u] = 0;
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if (f[j] > x) continue;
if (dis[j] > dis[u] + w[i])
{
dis[j] = dis[u] + w[i];
if (!st[j]) { q.push(j); st[j] = 1; }
}
}
}
if (dis[n] < b) return true;
else return false;
}
signed main()
{
memset(h, -1, sizeof h);
scanf("%lld%lld%lld", &n, &m, &b);
int l = 0, r = 0;
for (int i = 1; i <= n; i ++) { scanf("%lld", &f[i]); r = max(r, f[i]); }
l = max(f[1], f[n]);
while (m --)
{
int a, b, c; scanf("%lld%lld%lld", &a, &b, &c);
add(a, b, c), add(b, a, c);
}
if (!spfa(inf)) printf("AFK\n");
else
{
while (l < r)
{
int mid = l + r >> 1;
if (spfa(mid)) r = mid;
else l = mid + 1;
}
printf("%lld\n", l);
}
return 0;
}