codeUp 2031 To fill or not to fill 复杂贪心
2031: To Fill or Not to Fill
時間限制:?1 Sec??內存限制:?32 MB
提交:?599??解決:?132
With highways available, driving a car from Hangzhou to any other city is easy. But since the tank capacity of a car is limited, we have to find gas stations on the way from time to time. Different gas station may give different price. You are asked to carefully design the cheapest route to go.
Input Specification:
Each input file contains one test case. For each case, the first line contains 4 positive numbers: Cmax?(<= 100), the maximum capacity of the tank; D (<=30000), the distance between Hangzhou and the destination city; Davg?(<=20), the average distance per unit gas that the car can run; and N (<= 500), the total number of gas stations. Then N lines follow, each contains a pair of non-negative numbers: Pi, the unit gas price, and Di?(<=D), the distance between this station and Hangzhou, for i=1,...N. All the numbers in a line are separated by a space.
Output Specification:
For each test case, print the cheapest price in a line, accurate up to 2 decimal places. It is assumed that the tank is empty at the beginning. If it is impossible to reach the destination, print "The maximum travel distance = X" where X is the maximum possible distance the car can run, accurate up to 2 decimal places.
Sample Input 1:
50 1300 12 8
6.00 1250
7.00 600
7.00 150
7.10 0
7.20 200
7.50 400
7.30 1000
6.85 300
Sample Output 1:
749.17
Sample Input 2:
50 1300 12 2
7.10 0
7.00 600
Sample Output 2:
The maximum travel distance = 1200.00
?
題意就是從起點到終點有很多的加油站 每個加油站有距離起點的距離和單價?我們從起點開車到終點 開始油量為0 要盡可能走到終點 問所求的最小花費是多少?如果走不到終點 就輸出最遠距離。
一開始給出油箱大小,到終點的距離,還有每單價油可以走的里程數,以及加油站的信息
?
分析:
由于這個問題邏輯比較復雜 可以先研究樣例
假設汽車從起點S到終點E必須通過加一次油到達 可達范圍內有多個價格不一的加油站?
如果可達范圍內有更便宜的G 我們要選擇那個加油站續命 先加夠到這個加油站G的油 在到G處加新的油 這樣就相當于從起點到G再到終點的松弛 可以通過這個加油站把后面的路程的花費給減小“松弛”掉??
如果選擇某個并不是選擇可達范圍內最靠前的更便宜的加油站去加油站
如果選擇了一個較遠的,花費更大的站A 那么就必然導致起點加油變多花費變多,從A站新加的油到終點的這段距離花費變多 雖然路程變小 從全局來看 兩種不同的選擇花費不同的路段里 第二段從G到A花費變多 從A到終點E花費也變多?從而導致全局花費更大
如果選擇了一個較近的花費更大的站B 那么從起點S到B花費不變 那么從B到G花費變多 從G到終點花費也變多 ?從而導致全局更大的花費
所以在當前站 選擇可達范圍內最近的且更便宜的能夠帶來更小的局部最優 從而獲得更小的全局花費
如果沒有更便宜的?
那么就要在初始S加滿 這樣才能盡可能少加更貴的油 從而減小花費
那么選擇所有比初始S貴的里面最便宜G的? 那么從S到G花費起點S的油錢 從G到終點E 再化一部分新加的G站油錢 如果不是這樣選 得到的花費只會更大 怎么呢?
我們來看 這種情況下 續命油的油量是確定的 因為我前面加滿了?
如果選擇一個更近的站A但并不是可選加油站中最便宜的 那么從起點S到A花費不變,從A到G花費不變 但到終點需要加一次油 這時需要加的油會更貴一點(A站油錢) 從而全局花費更大
如果選擇一個更遠的站B但并不是可選加油站中最便宜的 那么起點到G花費不變 G到B花費不變?B到終點E 需要續一次油 花費變大(B站油錢)
所以在這種?分支下 我們也要選擇貴中最便宜的那個去加油 從而獲得全局最優
我們要找的續命的加油站 必須是可達范圍里最便宜的 只有這樣 才能通過這個最便宜的加油站 獲取盡可能便宜的局部最優花費 這樣再去選?
你有可能會有疑問
如果我們想G走著走著發現一個可達范圍內更便宜站P的怎么辦 即便如此 我們也要先到G站 看看能不能不加油直接走到P站 不過不可能! 因為P是G站決策之前的可達范圍之外的站 必然不可能不加油走到P站 所以我們有必要中間續油 那么續油的話 只能在G續油 因為G是最相對便宜的 我們只有先到了G再看看需要續多少油到更便宜的加油站去 如果沒有更便宜的加油站 則繼續選擇可達范圍內所有更貴的里面最便宜的? 所以整個過程就是
局部最優+局部最優+...+局部最優 = 全局最優
?
于是這個問題的邏輯大致就是如此 對每個加油站執行相同的邏輯 我們發現這樣的話就是貪心策略 每到一個加油站 在能到達的范圍內選擇局部最優策略 這樣走下來就能得到全局最優策略 如果在加油站不進行局部最優的策略 那么就必然導致花費變大
如果起始點沒有加油站 那么就輸出0 因為加不到油必然走不出去
否則:
看看加滿油的話 能到達的范圍內 有沒有加油站?
? ? ? ? ? ? ? ? ? ? ?如果沒有 那么就加滿油盡可能跑 能跑多遠就輸出多遠
? ? ? ? ? ? ? ? ? ? ?如果有加油站 看看有沒有一個加油站是他能到達的范圍內且離當前點比較近的?我們設此站位G站
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?如果有 我們就買剛好到G站的油量:因為到了G站買油可以得到更便宜的價格 從而盡可能的得到更小的花費? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?如果沒有 全都是比當前站更貴的加油站 那么就要從貴中選一個最便宜的設為H站 我們要走到那里繼續買油才能盡可能的減小花費 注意 這時要從當前站加滿油 因為H站的油是更貴的 但是又不能因為油貴而不走 還是要盡可能往前走的 這時如果不從H站買 從其他站買 只會導致更多的花費??所以我們要盡可能少的從H站買油 我們到了H站要站在H站的位置考慮更優的花費時 再從H站買油 故從當前站要加滿油 然后去向H站???
?
由于本題需要維護的參數比較多 邏輯比較復雜 還是要想清楚邏輯后 把變量寫的可讀性高點 才能少出bug
時間復雜度:O(n^(所能到達的范圍中的加油站個數))<O(n^2)<1000ms
?
#include<cstdio> #include<cstring> #include<iostream> #include<map> #include<cmath> #include<algorithm> #include<set> #include<vector> #include<climits> #define Equal(a,b) (fabs((a)-(b))<=eps) #define LessEqu(a,b) (((a)-(b))<=eps) #define Lessthan(a,b) (((a)-(b))<-eps) #define Morethan(a,b) (((a)-(b))>=eps) #define MoreEqu(a,b) (((a)-(b))>=-eps) const double eps = 1e-5; using namespace std; typedef long long ll; struct station{double cost;double dis; }S[510]; bool cmp(station a,station b){return Lessthan(a.dis,b.dis); } int main(){double c,dis,avg;int sta;ios::sync_with_stdio(0);cin>>c>>dis>>avg>>sta;for(int i=1;i<=sta;i++){cin>>S[i].cost>>S[i].dis;}double Lowest = S[1].cost;for(int i=2;i<=sta;i++){if(Lessthan(S[i].cost,Lowest)){Lowest = S[i].cost;}}sort(S+1,S+1+sta,cmp);if(!Equal(S[1].dis,0.0)){cout<<"The maximum travel distance = 0.00"<<endl;return 0;}bool f=0;S[sta+1].cost = 0,S[sta+1].dis = dis;double exp=0,canadd=c,distans=0,cut=0,unit=c;double costoil,oil = 0;bool fal = 0;for(int i=1;i<sta+1;i++){oil = (distans-S[i].dis)/avg;double Maxlim = S[i].dis + c*avg;double CMP = S[i].cost;int j,u=i;for(j=i+1;j<=sta+1&&LessEqu(S[j].dis,Maxlim);j++){if(Lessthan(S[j].cost,CMP)){CMP = S[j].cost;u = j;break;}}if(u==i&&j==i+1){//后面沒加油站distans = Maxlim;fal = 1;break;}if(u!=i){//有個更便宜的unit = (S[u].dis-distans)/avg;//減去的是什么很關鍵exp+=S[i].cost*unit;// canadd = unit;distans = S[u].dis;i = u-1;oil += unit;costoil = unit;continue;}//如果后面的都是比自己貴的CMP = S[i+1].cost;u = i+1;for(int j=i+2;j<=sta+1&&LessEqu(S[j].dis,Maxlim);j++){if(LessEqu(S[j].cost,CMP)){//盡可能少買 也就是盡可能遠CMP = S[j].cost;u = j;}}canadd = c-oil;distans += (canadd)*avg;exp+=canadd*S[i].cost;costoil = (S[u].dis-S[i].dis)/avg;oil=c;i = u-1;}if(fal)printf("The maximum travel distance = %.2f\n",distans);else printf("%.2f\n",round(exp*100)/100);return 0; }?
總結
以上是生活随笔為你收集整理的codeUp 2031 To fill or not to fill 复杂贪心的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 做免费的EDM,EmailCar看中的是
- 下一篇: 罗技 GHUB驱动的官方下载网址