读题读了好久,,,
有 个点,
条双向边 ,每个点有权值
,每条边有权值
。 总能量值为
, 经过边时 将会消耗 能量值。
要求:成功从 号点到达
号点(到达时 能量值
) 求 使 中途经过的 最大的点权 最小 ,输出此值
注明 来源 :luogu 题解区 (非本人)
【 题目解析 】
最大点权最小 -> 二分
二分 + Spfa 检验
因为 最后 要求输出 最小的 点权 ,因此我们 二分 点权(注意边界)
judge 的时候,关于 的松弛操作:
点要满足
当前二分的点权才松弛
最后判断 这样走下来的 到 的最短路 长度是否小于
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define LL long long
#define inf 0x7f7f7f7f
#define inff 0x7f7f7f7f7f7f7f7f
using namespace std;
inline int wread(){
char c(getchar ());int wans(0),flag(1);
while (c<'0' || c>'9'){if (c=='-') flag=-1; c=getchar ();}
while (c>='0' && c<='9'){wans=wans*10+c-'0';c=getchar ();}
return wans*=flag;
}
inline LL ll_wread(){
char c(getchar ());LL wans(0),flag(1);
while (c<'0' || c>'9'){if (c=='-') flag=-1; c=getchar ();}
while (c>='0' && c<='9'){wans=wans*10+c-'0';c=getchar ();}
return wans*=flag;
}
int n,m;
LL b,f[10005];
int K,hed[10005];
struct node{int v,nxt;LL w;}e[100005];
void ad (int u,int v,LL w){e[++K].v=v;e[K].w=w;e[K].nxt=hed[u];hed[u]=K;}
int que[100005],h,t;
LL dis[10005];
bool ins[10005];
bool jud (LL mon){// dian
if (f[1]>mon || f[n]>mon ) return false;
memset (ins,false,sizeof ins);
for (int i(1);i<=n;++i)
dis[i]=inff;
h=0,t=0;
que[++h]=1;
dis[1]=0;
ins[1]=true;
while (t<h){
int x(que[++t]);ins[x]=false;
for (int i(hed[x]);i!=-1;i=e[i].nxt){
int v(e[i].v);
if ( dis[v] > dis[x] + e[i].w && f[v]<=mon ) dis[v] = dis[x] + e[i].w;
else continue;
if (!ins[v]) que[++h]=v;
}
}
if (dis[n] <= b) return true;
return false;
}
int main (){
memset (hed,-1,sizeof hed);
LL l=inff,r=-inff;LL min_a,max_a;
n=wread();m=wread();b=ll_wread();
for (int i(1);i<=n;++i)
f[i]=ll_wread(),l=min(l,f[i]), r=max(r,f[i]);
for (int i(1);i<=m;++i){
int u(wread()),v(wread());LL w(ll_wread());
ad (u,v,w);ad (v,u,w);
}
LL ans=inff;
min_a=l;max_a=r;
r++;
l--;
while (l<r){
LL mid((l+r)/2);//hua fei
if (mid>max_a) r=mid;
else if (mid<min_a) l=mid+1;
else {
if (jud(mid)) r=mid,ans=min (ans,mid);
else l=mid+1;
}
}
if (ans==inff) puts("AFK");
else printf("%lld\n",ans);
return 0;
}