洛谷 P1951 收费站
题目分析:题目中是要求从s到t的路径上,经过的收费站所收取的费用的最大值最小。所以,我们可以想到二分答案!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<deque>
#define fp(i,a,b) for(register int i=a;i<=b;++i)
using namespace std;
struct arr{
int nd,nx,co;
}bot[100100];
int n,m,b,cnt,s,t;
long long head[20000],dist[20000],vis[20000],w[20000],cost[20000];
inline int read(){
int x=0,w=1;char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch-48),ch=getchar();
return x*w;
}
inline int cmp(long long a,long long b){return a<b;}
inline void add(int a,int b,int c){bot[++cnt].nd=b;bot[cnt].nx=head[a];bot[cnt].co=c;head[a]=cnt;}
inline int SPFA(int x){
if(x<w[s]) return 0;//原点也要包含在这里面
fp(i,1,n) dist[i]=1147483647,vis[i]=0;
deque<int>q;
dist[s]=0;q.push_back(s);vis[s]=1;
while(!q.empty()){
int u=q.front(),v;q.pop_front();
vis[u]=0;
for(register int i=head[u];i;i=bot[i].nx){
int v=bot[i].nd;
if(w[v]<=x&&dist[v]>dist[u]+bot[i].co){
//除了普通的SPFA的判断,还要加一个当前点的收取费用是否是小于等于二分的x值
dist[v]=dist[u]+bot[i].co;
if(!vis[v]){
vis[v]=1;
if(q.empty()||dist[v]>dist[q.front()])
q.push_back(v);
else q.push_front(v);
}
}
}
}
return dist[t]<b; //返回值
}
int main(){
n=read();m=read();s=read();t=read();b=read();
fp(i,1,n) w[i]=cost[i]=read();
fp(i,1,m){int u=read(),v=read(),ww=read();add(u,v,ww);add(v,u,ww); }
//双向边
sort(1+cost,1+n+cost,cmp);
int l=1,r=n, mid,ans=-1;
while(l<=r){//二分答案部分
mid=(l+r)>>1;
if(SPFA(cost[mid])) ans=cost[mid],r=mid-1;
else l=mid+1;
}
cout<<ans<<endl;
}