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)可达站里存在比当前站价钱低的站,那么此时就不能加满,加满就“亏了”,一定要留到下个站加气,要够“贪”。
这是一个比较复杂的贪心算法,2012年浙江大学机试题目,全场只有三个人AC
代码如下:
#include <stdio.h> #include <algorithm> using namespace std; struct station { float price; float dis; bool operator <(const station & B)const { return price<B.price; } }STT[500]; int NextStation(station *STT,int CurPos,int N,int MaxDis) { int NextPos; int i; for(i=0;i<N;i++) { if(STT[i].dis-STT[CurPos].dis<=MaxDis&&STT[i].dis-STT[CurPos].dis>0) { NextPos=i; break; } } if(NextPos>CurPos) return NextPos; int MinPos=NextPos; //如果存在比当前站价钱低的站点则找距离最近的点 for(i=0;i<CurPos;i++) { if(STT[i].dis-STT[CurPos].dis<=MaxDis&&STT[i].dis-STT[CurPos].dis>0&&STT[i].dis<STT[MinPos].dis) { MinPos=i; } } NextPos=MinPos; return NextPos; } int main(int argc, char** argv) { float Cap;//老司机车的最大气量 float Dis;//总距离 float Davg;//单位气量走的距离 int N;//气站的数量 while(scanf("%f%f%f%d",&Cap,&Dis,&Davg,&N)!=EOF) { int i; for(i=0;i<N;i++) { scanf("%f%f",&STT[i].price,&STT[i].dis); } //按价钱升序排列 sort(STT,STT+N); float MaxDis=Cap*Davg;//满气能跑的距离 //有两种情况:1、当前站前面最大距离内无价钱更低的站 2、有价钱更低的站 int CurPos;//当前所在气站 int NextPos;//能够达到的最小距离内的价钱最低的气站的位置 float NextPrice; float CurDis=0; float money=0; float left=0; bool finished=false; bool start=true; int Last=0;//最后一个站点 for(i=0;i<N;i++) { if(STT[Last].dis<STT[i].dis) { Last=i; } } //设置当前站为起始站 for(i=0;i<N;i++) { if(STT[i].dis==0) { CurPos=i; break; } } //无起始站 if(i==N) { printf("The maximum travel distance = 0.00\n"); } else{ while(CurDis<Dis&&CurPos<N) { //如果是最后一个点,要判断能不能跑完 if(CurPos==Last) { //如果加满也跑不完 if(STT[CurPos].dis+MaxDis<Dis) { CurDis+=MaxDis; break; } //如果可以跑完 else { money+=(Dis-CurDis)/Davg*STT[CurPos].price; CurDis=Dis; finished=true; break; } } int i; //先找到下一个能到达且价钱最低的站点, NextPos=NextStation(STT,CurPos,N,MaxDis); //如果找不到 ,退出循环 if(i==N) { CurDis+=MaxDis; break; } //如果下个站点价钱比当前的低,则不加满,只加到够用到下个站即可,则left变为0 if(NextPos<CurPos) { //如果剩余不足走到下一站,再加一点够到地方就行 if((STT[NextPos].dis-STT[CurPos].dis)/Davg-left>0) { money+=((STT[NextPos].dis-STT[CurPos].dis)/Davg-left)*STT[CurPos].price; CurDis=STT[NextPos].dis; CurPos=NextPos; left=0; } //如果剩余多于到达下一站的量,就不用加油了 else { left-=(STT[NextPos].dis-STT[CurPos].dis)/Davg; CurDis=STT[NextPos].dis; CurPos=NextPos; } //关于这两个判断我也没有仔细想到底需不需要保留下来,不过保留下来也便于理解吧 (嗯,后来思考了一下,其实并不存在这个else的情况,因为到达下一站一定是要加气才可到达下下站的 ) } //如果下个站点的价钱比当前的高,则加满 else if(NextPos>CurPos) { //如果能直接到头,也不用加满 if(CurDis+MaxDis>=Dis) { money+=(Dis-CurDis)/Davg*STT[CurPos].price; finished=true; break; } money+=(Cap-left)*STT[CurPos].price; left=Cap; left-=(STT[NextPos].dis-STT[CurPos].dis)/Davg; CurDis=STT[NextPos].dis; CurPos=NextPos; } } if(finished==false) printf("The maximum travel distance = %.2f\n",CurDis); if(finished==true) { printf("%.2f\n",money); } } } return 0; }