1. 程式人生 > >通往奧格瑞瑪的道路——二分加SPFA

通往奧格瑞瑪的道路——二分加SPFA

play -1 類的方法 check cin code stream fff clas

  因為所求的最優解不關乎到達目的地時的血量,所以我們只需考慮能否到達和如何取到最優解這兩個問題。如果用貪心之類的方法,可以想象這個題目會變得無比復雜,所以我們換一種思路想想。題目要求的是在能夠到達奧格瑞瑪的情況下,一路上所花費的過路費的最大值的最小可能值。我們可以想象,如果給定一個過路費的最大值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 }
Method_01

  洛谷 664ms

通往奧格瑞瑪的道路——二分加SPFA