通往奥格瑞玛的道路——二分加SPFA
Posted Darkins
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通往奥格瑞玛的道路——二分加SPFA相关的知识,希望对你有一定的参考价值。
因为所求的最优解不关乎到达目的地时的血量,所以我们只需考虑能否到达和如何取到最优解这两个问题。如果用贪心之类的方法,可以想象这个题目会变得无比复杂,所以我们换一种思路想想。题目要求的是在能够到达奥格瑞玛的情况下,一路上所花费的过路费的最大值的最小可能值。我们可以想象,如果给定一个过路费的最大值Max,那么就相当于是从图中删去了过路费大于Max 的所有点。我们显然可以用单源最短路算法判断,删去一部分点后歪嘴哦能否到达奥格瑞玛,即从点1 到点n 的距离是否大于等于数据中给出的初始血量b。这样一来,更不难想到,Max 的值越小,歪嘴哦能成功回城的“希望”就越小,因为Max 的值越小,图中的点越少。那么,我们就可以从所有城市的过路费数组中二分出答案了,只需用SPFA 简单验证解的可行性即可。另外再多说几句,看我的代码就可以知道,歪嘴哦不能回到奥格瑞玛,即输出“AFK”的情况有且仅有一种:不论Max 怎么大,他都无法回到奥格瑞玛,这不难想到,采用预判的方式判断无解还可以稍微减少处理数据的复杂程度。并且,Max 的值一定要大于等于点1 和点n 的过路费。
1 #include<queue> 2 #include<vector> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cstdio> 8 using namespace std; 9 const long long N=11111,INF=0x3fffffffffffffff; 10 long long n,m,b,f[N],val[N],l,r,res; 11 vector<long long> gr[N],dis[N]; 12 13 bool check(long long v){ 14 long long d[N]; 15 bool inq[N]; 16 queue<long long> q; 17 memset(inq,0,sizeof inq);memset(d,0x3f,sizeof d); 18 q.push(1);inq[1]=true;d[1]=0; 19 while(!q.empty()){ 20 long long x=q.front();q.pop();inq[x]=false; 21 for(long long i=0;i<gr[x].size();i++) 22 if(f[gr[x][i]]<=v&&d[x]+dis[x][i]<d[gr[x][i]]){ 23 d[gr[x][i]]=d[x]+dis[x][i]; 24 if(!inq[gr[x][i]])q.push(gr[x][i]),inq[gr[x][i]]=true; 25 } 26 } 27 return f[n]<=v&&d[n]<b; 28 } 29 30 int main(){ 31 cin>>n>>m>>b; 32 for(long long i=1;i<=n;i++){scanf("%lld",f+i);r+=f[i];val[i]=f[i];} 33 sort(val+1,val+1+n); 34 35 while(m--){ 36 long long x,y,v;scanf("%lld%lld%lld",&x,&y,&v); 37 gr[x].push_back(y);dis[x].push_back(v); 38 gr[y].push_back(x);dis[y].push_back(v); 39 } 40 41 if(!check(INF)){ 42 cout<<"AFK"<<endl; 43 return 0; 44 } 45 46 while(val[l]<max(f[1],f[n]))l++;l--; 47 r=n; 48 while(l<=r){ 49 m=(l+r)>>1; 50 if(check(val[m]))r=m-1,res=val[m]; 51 else l=m+1; 52 } 53 cout<<res<<endl; 54 return 0; 55 }
洛谷 664ms
以上是关于通往奥格瑞玛的道路——二分加SPFA的主要内容,如果未能解决你的问题,请参考以下文章
洛谷 P1462 通往奥格瑞玛的道路(spfa+二分搜索)(4boy)
luogu题解 P1462 通往奥格瑞玛的道路二分+spfa
洛谷P1462 通往奥格瑞玛的道路[二分答案 spfa 离散化]