题意:一个无向图,每个点有一个花费,求在从 1−n 1 − n 的边权和 <=b <= b <script type="math/tex" id="MathJax-Element-182"><=b</script>的情况下,经过的所有点中最大的一次花费的最小值是多少。
求最大值最小,我们常用二分答案的做法,二分最大花费的最小值。一开始先跑一遍 spfa s p f a ,如果 n n 不可达或此时的,就输出不可行。对于每一次二分到的最大花费 s s ,我们跑一次,在跑 spfa s p f a 的时候注意松弛时搜到的点的花费要 <=s <= s <script type="math/tex" id="MathJax-Element-189"><=s</script>,二分的判断条件就是 dis[n]是否<=b d i s [ n ] 是 否 <= b 。
#include<bits/stdc++.h>
using namespace std;
struct node
{
int next,to,dis,from;
}e[1001000];
int head[1001000],num,n,m,b;
bool inqueue[1001000];
int dis[1001000],f[1001000];
void add(int from,int to,int dis)
{
e[++num].next=head[from];
e[num].from=from;
e[num].to=to;
e[num].dis=dis;
head[from]=num;
}
void spfa(int s)
{
queue<int> q;
while(!q.empty())
q.pop();
for(int i=1;i<=n;++i)
dis[i]=1<<30;
dis[1]=0;
q.push(1);
inqueue[1]=true;
while(!q.empty())
{
int x=q.front();
q.pop();
inqueue[x]=false;
for(int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(dis[v]>dis[x]+e[i].dis&&f[v]<=s)
{
dis[v]=dis[x]+e[i].dis;
if(!inqueue[v])
{
inqueue[v]=true;
q.push(v);
}
}
}
}
}
bool judge(int mid)
{
spfa(mid);
if(dis[n]>b)
return false;
return true;
}
int l,r;
int main()
{
cin>>n>>m>>b;
for(int i=1;i<=n;++i)
{
cin>>f[i];
r=max(r,f[i]);
}
l=max(f[1],f[n]);
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
add(x,y,z);
add(y,x,z);
}
spfa(r);
if(dis[n]==1<<30||dis[n]>b)
{
cout<<"AFK";
return 0;
}
while(r>=l)
{
int mid=(l+r)/2;
if(judge(mid))
r=mid-1;
else
l=mid+1;
}
cout<<l;
return 0;
}