spfa进阶使用二分+SLF(洛谷1951 收费站_NOI导刊2009提高)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spfa进阶使用二分+SLF(洛谷1951 收费站_NOI导刊2009提高)相关的知识,希望对你有一定的参考价值。
在某个遥远的国家里,有n个城市。编号为1,2,3,…,n。
这个国家的政府修建了m条双向的公路。每条公路连接着两个城市。沿着某条公路,开车从一个城市到另一个城市,需要花费一定的汽油。
开车每经过一个城市,都会被收取一定的费用(包括起点和终点城市)。所有的收费站都在城市中,在城市间的公路上没有任何的收费站。
小红现在要开车从城市u到城市v(1<=u,v<=n)。她的车最多可以装下s升的汽油。在出发的时候,车的油箱是满的,并且她在路上不想加油。
在路上,每经过一个城市,她都要交一定的费用。如果某次交的费用比较多,她的心情就会变得很糟。所以她想知道,在她能到达目的地的前提下,她交的费用中最多的一次最少是多少。这个问题对于她来说太难了,于是她找到了聪明的你,你能帮帮她吗?
输入格式:
第一行5个正整数,n,m,u,v,s,分别表示有n个城市,m条公路,从城市u到城市v,车的油箱的容量为s升。
接下来的有n行,每行1个整数,fi表示经过城市i,需要交费fi元。
再接下来有m行,每行3个正整数,ai,bi,ci(1<=ai,bi<=n),表示城市ai和城市bi之间有一条公路,如果从城市ai到城市bi,或者从城市bi到城市ai,需要ci升的汽油。
输出格式:
仅一个整数,表示小红交费最多的一次的最小值。
如果她无法到达城市v,输出-1.
4 4 2 3 8 8 5 6 10 2 1 2 2 4 1 1 3 4 3 4 3
8
1 #include<iostream> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstring> 5 #include<cstdio> 6 #include<queue> 7 #define maxn 150000 8 #define LL long long 9 10 using namespace std; 11 LL n,m,u,v,s; 12 13 struct Edge 14 { 15 LL next,to,w; 16 }; 17 struct Edge edge[maxn]; 18 LL cnt=0; 19 LL head[maxn]; 20 LL val[maxn]; 21 22 void add(LL u,LL v,LL ww) 23 { 24 edge[++cnt].to=v; 25 edge[cnt].w=ww; 26 edge[cnt].next=head[u]; 27 head[u]=cnt; 28 } 29 30 deque<LL> q;//双向队列 31 LL book[maxn],dis[maxn]; 32 33 int spfa(LL x)//最大的价值 34 { 35 if(val[u]>x||val[v]>x) return 0;//剪枝 36 memset(book,0,sizeof(book)); 37 38 for(LL i=1;i<=n;i++) 39 dis[i]=1e12; 40 41 book[u]=1;dis[u]=0; 42 q.push_back(u); 43 44 while(!q.empty()) 45 { 46 LL fr=q.front(); 47 book[fr]=0;q.pop_front(); 48 for(LL i=head[fr];i;i=edge[i].next) 49 { 50 LL j=edge[i].to; 51 if(val[j]>x) continue; 52 if(dis[j]>dis[fr]+edge[i].w) 53 { 54 dis[j]=dis[fr]+edge[i].w; 55 if(!book[j]) 56 { 57 if(q.empty()) q.push_back(j); 58 else 59 { 60 if(dis[j]<dis[q.front()]) 61 q.push_front(j);//在前部插入 62 else 63 q.push_back(j); 64 } 65 book[j]=1;//标记已经入队 66 } 67 } 68 } 69 } 70 if(dis[v]<=s) return 1; 71 return 0; 72 } 73 74 75 int main() 76 { LL l=1,r=0; 77 cin>>n>>m>>u>>v>>s; 78 for(LL i=1;i<=n;i++) 79 { 80 cin>>val[i]; 81 r=max(val[i],r); 82 } 83 LL t1,t2,t3; 84 for(LL i=1;i<=m;i++) 85 { 86 cin>>t1>>t2>>t3; 87 add(t1,t2,t3); 88 add(t2,t1,t3); 89 } 90 if(!spfa(1e13)) 91 { 92 cout<<-1; 93 return 0; 94 } 95 while(l<=r) 96 { 97 LL mid=(l+r)>>1; 98 if(spfa(mid))r=mid-1; 99 else l=mid+1; 100 } 101 cout<<l<<endl; 102 return 0; 103 }
90分的代码,还需要优化
以上是关于spfa进阶使用二分+SLF(洛谷1951 收费站_NOI导刊2009提高)的主要内容,如果未能解决你的问题,请参考以下文章
洛谷P1462 通往奥格瑞玛的道路 二分答案+最短路SPFA
洛谷 P1462 通往奥格瑞玛的道路(spfa+二分搜索)(4boy)