1033. To Fill or Not to Fill (25)
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 300Sample Output 1:
749.17Sample Input 2:
50 1300 12 2 7.10 0 7.00 600Sample Output 2:
The maximum travel distance = 1200.00
1 /* 2 分析: 3 很明顯,這道題的思路是貪心,也就是要用盡可能少的錢,要去盡可能遠的地方。 4 那么,像這種貪心的題目,怎么去思考呢? 5 首先,今天聽到戴龍翱(ZJU大牛)提到的一點,對於貪心的題目,測試樣例,必須自己去體會一遍,這樣,很有可能會給我們帶來不少啟發。 6 那么,我們就一起來過一遍測試樣例吧: 7 8 Sample Input 1: 9 50 1300 12 8 10 6.00 1250 11 7.00 600 12 7.00 150 13 7.10 0 14 7.20 200 15 7.50 400 16 7.30 1000 17 6.85 300 18 19 Sample Output 1: 20 749.17 21 22 先畫個圖再看 23 1:起點,肯定是要加油的,不然跑都跑不起來,那么,問題來了——加多少? 24 讓我們先來觀察一下,油箱加滿之后,最遠能跑600;也就是說,如果我現在在起點把油箱加滿的話,[0,600]都是我可以達到的路程范圍; 25 好了,那么,我們只需要看這個范圍內的如何做出貪心策略; 26 起點處的油價是7.1,如果之后遇到的第一個加油站A油價小於7.1,那么,在A之后不管是什么情況,我們都應該加油(至於要加多少,還不能確定), 27 因為至少在當前狀態下,這樣做是最“貪婪”的。 28 2:通過1的分析,我們選擇了加油站B。而且值得強調的是,我們在起點A加的油跑到B時是正好用完的狀態。 29 這時,我們站在了B點,B點最遠能到750(150+600),我們又如何根據貪心算法來做出貪婪的決策呢? 30 B處的油價是7,顯然,750之前的加油站有很多,油價有比7小的,比7大的,也有等於7的。那么,貪婪的你,一定不會傻到去選擇一個油價貴的(如C、E) 31 因為我完全可以到達比7小的加油站再加油,為什么要去比7大的加油站加油呢? 32 so,我們選擇了D(油價6.85),而且,D的油價比當前的便宜,所以我們加油只要夠從B——>D就好,加多了就不符合我貪婪的本性了! 33 3:到了D之后,可以說是比較開心的,因為在他[300,300+600]的范圍內這價是最便宜的,此時不加更待何時!?因為是最便宜的,所以,為了貪,必須加滿! 34 加滿了之后,最遠可以到900(300+600),那么,在900之前,我們會遇到E、F,且F油價較E要便宜一些,因此,為了到達目的地,我們不得不到F加油。 35 4:和之前的情況有所不同的是,這次,我們到目的地的時候,還是有油剩余的(600-300<600),而且剩余的油夠跑300(即可以跑到900)。 36 那么,我們在F加多少的油呢? 37 站在F的位置,我們開始思考。距離400有一個加油站G,可是油價要7.3,坑爹呢!這么貴! 38 可是,就算F加滿了,我們也只能跑到1200(600+600),所以,沒辦法,為了到達目的地,我們不得不到G加,但是,這里要注意,因為G比F的油價要貴, 39 所以,為了貪,我們會在F把油加滿,(在能夠達到目的地的前提下,盡可能在貴的地方少加點油,在便宜的地方多加點油——貪); 40 5:到了G之后,計算了此時郵箱還剩下的油狗刨200,也就是說,我們在貴的的地方G只需要加50(1250-1000-200),能到H即可,因為H的油價是最便宜(沒有之一), 41 在[1000,1000+600]的范圍內,是最便宜的,so,就這樣走到了H 42 6:走到了H之后,就不用多想了,H之后也沒有加油站了,而且加滿能夠到目的地I的油量就夠了。 43 44 經過了以上分析之后,要開始對以上的各個情況進行抽象,即把遇到的情況分類(要包括所有的情況),並且,基於貪心的思想去考慮不同的情況下,做出何種決策 45 處在當前加油站(起點加油站)的情況下 46 情況1:600米范圍內,有目的地——計算恰好能到目的地的油量 【6】 47 情況2:600米范圍內沒有加油站,無論油價多貴——加滿——能跑多遠算多遠 48 情況3:600米范圍內有加油站: 49 a:有比當前加油站的油價更便宜的加油站——加到恰好能到那個最近的油站的油量 【1】【2】【5】 50 (注:1、如果有多個便宜的,還是要先選取最近的那個,而不是最便宜的那個;2、可能還有油剩余) 51 b:沒有比當前加油站的油價更便宜的加油站——加滿,然后在600范圍內找到最便宜的加油站加油 【3】【4】 52 53 再來看第二組數據: 54 Sample Input 2: 55 50 1300 12 2 56 7.10 0 57 7.00 600 58 59 Sample Output 2: 60 The maximum travel distance = 1200.00 61 62 分析過程: 63 1:600的范圍內(包括600),有加油站,而且比當前的油價要便宜,因此,屬於情況3—a,故,我們加到恰好能到,這里比較特殊的是,只有加滿才恰好能到, 64 注意,這里不能歸為情況2,因為情況2的結果對應着一定無法到達目的地,所以,當前的狀態還無法判斷出能不能到達目的地; 65 2:600范圍內,沒有加油站,這里屬於情況2,能跑多遠跑多遠,因為已經無法到達目的地了,只能盡可能地跑更遠 66 67 經過以上的分析,就可以開始嘗試地寫代碼了 68 特殊的情況優化: 69 1:起點沒有加油站 70 2:起點即終點 71 72 主要的幾個關鍵點,或者說是行駛的過程中需要記錄些什么信息: 73 1:到達當前加油站的油量——因為,你要計算還需要加多少油,所以,總共需要的油量—現有的油量=在當前加油站要加的油量 74 */ 75 #include<stdio.h> 76 #include<algorithm> 77 #include<iostream> 78 using namespace std; 79 80 typedef struct 81 { 82 double pos; 83 double price; 84 }gasstation; 85 gasstation gasst[502]; 86 87 bool cmp(gasstation a,gasstation b) 88 { 89 if(a.pos<b.pos) 90 return true; 91 return false; 92 } 93 94 int main() 95 { 96 double Cmax,D,Davg; 97 int N; 98 scanf("%lf%lf%lf%d",&Cmax,&D,&Davg,&N); 99 int i; 100 for(i=0;i<N;i++) 101 scanf("%lf%lf",&gasst[i].price,&gasst[i].pos); 102 sort(gasst,gasst+N,cmp); 103 if(D==0) 104 { 105 printf("0.00\n"); 106 return 0; 107 } 108 if(gasst[0].pos!=0) 109 { 110 printf("The maximum travel distance = 0.00\n"); 111 return 0; 112 } 113 int curstnum=0; //當前所處的油站編號,即當前的位置 114 double curgas=0; //當前的油量 115 double curcost=0; //當前的花費 116 bool flag=false; //是否達到目的 117 double maxrundis=Cmax*Davg; //郵箱加滿最遠能行駛的距離 118 while(!flag) 119 { 120 bool tag=false; //最大距離內是否有加油站 121 bool ifcheaper=false; //是否有便宜的 122 double cheapestprice=10000; //找出最便宜的 123 int cheapestnum; //沒有更便宜的情況下,找出最便宜的 124 for(i=curstnum+1;i<N;i++) 125 { 126 if((gasst[i].pos-gasst[curstnum].pos)<=maxrundis) //范圍內 127 { 128 tag=true; //有加油站 129 if(gasst[i].price<gasst[curstnum].price) //情況3-a 130 { //且有更便宜的 131 ifcheaper=true; 132 double dist=gasst[i].pos-gasst[curstnum].pos; 133 double needgas=dist/Davg-curgas; 134 curgas=0; 135 curcost+=(needgas*gasst[curstnum].price); 136 curstnum=i; 137 break; 138 } 139 if(gasst[i].price<cheapestprice) 140 { 141 cheapestprice=gasst[i].price; 142 cheapestnum=i; 143 } 144 } 145 else 146 break; 147 } 148 if(!ifcheaper&&(maxrundis>=(D-gasst[curstnum].pos))) //說明已經可以到達目的地了,情況1 149 { 150 double dist=D-gasst[curstnum].pos; 151 double needgas=dist/Davg-curgas; 152 curcost+=needgas*gasst[curstnum].price; 153 printf("%.2lf\n",curcost); 154 return 0; 155 } 156 if(tag&&!ifcheaper) //情況3-b 157 { 158 double needgas=Cmax-curgas; 159 curcost+=(needgas*gasst[curstnum].price); 160 double dist=gasst[cheapestnum].pos-gasst[curstnum].pos; 161 curgas=Cmax-dist/Davg; 162 curstnum=cheapestnum; 163 } 164 else if(!tag) //情況2 165 { 166 printf("The maximum travel distance = %.2lf\n",gasst[curstnum].pos+maxrundis); 167 return 0; 168 } 169 } 170 return 0; 171 }