思路
第一联想到最短路解决血量剩余最多的路径,但是这道题有一个条件,必须使路径上的最大的点最小。
那么我们可以把点权从小到大排序,然后二分查找最小的能到达奥格瑞玛的路径。
也就是说,我们设置当前二分到的点权为该条路上最大的点权,那么进行最短路的时候,我们需要判断通向的点是否小于当前二分到的点权,最后如果可以到达奥格瑞玛,我们就往小二分,否则就往大的点权二分。
代码
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 1e5 + 10;
const int MAXM = 5e5 + 10;
struct node {
int next ,to ,val;
}edge[MAXM];
int head[MAXN] ,cnt = 0;
void add (int from ,int to ,int val) {
edge[++ cnt].next = head[from];
head[from] = cnt;
edge[cnt].to = to;
edge[cnt].val = val;
}
int n ,m ,b;
int fi[MAXN] ,ui[MAXN];
int ans = 0;
bool SPFA (int top) {
int dis[MAXN] ,inq[MAXN];
memset (dis ,0x3f ,sizeof (dis));
memset (inq ,0 ,sizeof (inq));
queue <int > s;
s.push(1);
dis[1] = 0;
inq[1] = 1;
while (!s.empty()) {
int u = s.front();
s.pop();
inq[u] = 0;
for (int q = head[u];~ q;q = edge[q].next) {
int v = edge[q].to;
if (dis[u] + edge[q].val < dis[v] && ui[v] <= top) {
dis[v] = dis[u] + edge[q].val;
if (!inq[v]) {
inq[v] = 1;
s.push(v);
}
}
}
}
if (dis[n] <= b) {
return true;
}
return false;
}
int main () {
memset (head ,-1 ,sizeof (head));
scanf ("%d%d%d",&n ,&m ,&b);
for (int q = 1;q <= n;++ q)
scanf ("%d",&fi[q]) ,ui[q] = fi[q];
int from_ ,to_ ,val_;
for (int q = 1;q <= m;++ q) {
scanf ("%d%d%d",&from_ ,&to_ ,&val_);
add (from_ ,to_ ,val_) ,add (to_ ,from_ ,val_);
}
if (!SPFA (0x3f3f3f3f)) {
puts ("AFK");
return 0;
}
sort (fi + 1 ,fi + n + 1);
int l = 1 ,r = n;
while (l <= r) {
int mid = (l + r) >> 1;
if (SPFA (fi[mid])) {
ans = fi[mid];
r = mid - 1;
}
else l = mid + 1;
}
printf ("%d
",ans);
return 0;
}