题目大意:有n个城市,一个人要从1到n。每个城市有一个过路费,经过要付钱(起点终点也要)。城市间有道路连接,每条道路经过时会扣一些血。初始时有b点血。现在问你在能使血量不小于0到达终点时,所经过所有的城市中,收取过路费最大的城市收取过路费的最小值。
解题思路:本题是最小化最大值问题,可用二分答案。
判断答案时,SPFA跑一遍最短路,边权为扣的血量。
做SPFA时,不能经过收费大于当前的答案的点。
最后如果到n的距离(扣的血量)不超过初始血量b,则可行。
C++ Code:
#include<cstdio>
#include<cctype>
#include<cstring>
#include<queue>
#define ll long long
int n,m,blood,money[10005],head[10005];
ll d[10005];
bool vis[10005];
std::queue<int>q;
struct edge{
int to;ll dis;int nxt;
}e[100050];
inline int max(int a,int b){return a>b?a:b;}
inline int readint(){
char c=getchar();
for(;!isdigit(c);c=getchar());
int d=0;
for(;isdigit(c);c=getchar())
d=(d<<3)+(d<<1)+(c^'0');
return d;
}
bool ok(int mid){
memset(d,0x3f,sizeof d);
memset(vis,0,sizeof vis);
d[1]=0;
vis[1]=true;
q.push(1);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=false;
for(int i=head[u];i;i=e[i].nxt)
if(money[e[i].to]<=mid&&d[e[i].to]>d[u]+e[i].dis){
d[e[i].to]=d[u]+e[i].dis;
if(!vis[e[i].to]){
vis[e[i].to]=true;
q.push(e[i].to);
}
}
}
return d[n]<=blood;
}
int main(){
n=readint();
m=readint();
blood=readint();
memset(head,0,sizeof head);
int l,r=0;
for(int i=1;i<=n;++i)r=max(r,money[i]=readint());
l=max(money[1],money[n]);
for(int cnt=0;m--;){
int u=readint(),v=readint(),t=readint();
e[++cnt]=(edge){v,t,head[u]};
head[u]=cnt;
e[++cnt]=(edge){u,t,head[v]};
head[v]=cnt;
}
int ans=-11111;
while(l<=r){
int mid=(l+r)>>1;
if(ok(mid))r=(ans=mid)-1;else
l=mid+1;
}
if(ans==-11111)puts("AFK");else
printf("%d\n",ans);
return 0;
}