P1951 收费站_NOI导刊2009提高(2)
题目描述
在某个遥远的国家里,有n个城市。编号为1,2,3,…,n。
这个国家的政府修建了m条双向的公路。每条公路连接着两个城市。沿着某条公路,开车从一个城市到另一个城市,需要花费一定的汽油。
开车每经过一个城市,都会被收取一定的费用(包括起点和终点城市)。所有的收费站都在城市中,在城市间的公路上没有任何的收费站。
小红现在要开车从城市u到城市v(1<=u,v<=n)。她的车最多可以装下s升的汽油。在出发的时候,车的油箱是满的,并且她在路上不想加油。
在路上,每经过一个城市,她都要交一定的费用。如果某次交的费用比较多,她的心情就会变得很糟。所以她想知道,在她能到达目的地的前提下,她交的费用中最多的一次最少是多少。这个问题对于她来说太难了,于是她找到了聪明的你,你能帮帮她吗?
显然二分+SPFA
SPFA会超时,使用堆优化的SPFA
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define N 1010100 #define inf 0x7fffffff #define LL long long using namespace std; LL n,m,S,T,s,val[N],tot,head[N],ans; struct node { LL to,next,w; } e[N]; void add(LL u,LL v,LL w) { e[++tot].to=v,e[tot].next=head[u],head[u]=tot,e[tot].w=w; } struct npde{ int u; LL d; friend bool operator < (npde x,npde y){ return x.d>y.d; } }; priority_queue<npde>Q; LL d[N]; bool vis[N]; void spfa() { memset(d,0x7f,sizeof(d)); memset(vis,0,sizeof(vis)); d[S]=0; vis[S]=1; Q.push((npde){S,0}); while(!Q.empty()) { int u=Q.top().u,D=Q.top().d; Q.pop(); vis[u]=0; for(LL i=head[u]; i; i=e[i].next) { LL v=e[i].to; if(d[v]>d[u]+e[i].w) { d[v]=d[u]+e[i].w; if(!vis[v]) vis[v]=1,Q.push((npde){v,d[v]}); } } } } bool Spfa(LL X) { fill(d+1,d+1+n,inf); memset(vis,0,sizeof(vis)); d[S]=0; vis[S]=1; Q.push((npde){S,0}); while(!Q.empty()) { LL u=Q.top().u; Q.pop(); vis[u]=0; for(LL i=head[u]; i; i=e[i].next) { LL v=e[i].to; if(d[v]>d[u]+e[i].w&&val[v]<=X) { d[v]=d[u]+e[i].w; if(!vis[v]) vis[v]=1,Q.push((npde){v,d[v]}); } } } return d[T]<=s; } int main() { scanf("%lld%lld%lld%lld%lld",&n,&m,&S,&T,&s); for(LL i=1; i<=n; i++) scanf("%lld",&val[i]),val[0]=max(val[0],val[i]); for(LL u,v,w,i=1; i<=m; i++) { scanf("%lld%lld%lld",&u,&v,&w); add(u,v,w),add(v,u,w); } spfa(); if(d[T]>s) printf("-1"); else { LL l=val[S],r=val[0]; while(l<=r) { LL mid=(l+r)/2; if(Spfa(mid)) ans=mid,r=mid-1; else l=mid+1; } printf("%lld ",ans); } return 0; }