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 300
Sample Output 1:
Sample Input 2:
50 1300 12 2
7.10 0
7.00 600
Sample Output 2:
The maximum travel distance = 1200.00
本题陷阱很多,稍不注意就卡死了。。但是其实认真将用例看懂了,基本也就差不多了。总之难度在细节!!!
先明确题意:从起点开始沿着高速公路一直往前开,公路上每隔一段距离会有加油站,选择最优加油策略,使得
花最少的钱跑到指定的路程
以用例为例:如上图
先考虑简单:
达不到终点:
1.起点没有加油站。此时最远距离0
2.中间某两个相邻加油站之间的距离大于加满油能跑的最大距离(600)。次时最远距离为加油站距离+单次加满油 最远距离(600)
3.最后一站还到不了终点 最后一站距离+最大距离600
能达到终点:
先注意两点:1)在起点不一定加满油 2)能加油开到终点(剩余路程<600),也不一定在本站就加满一次跑到终点
贪心要领: 要遵守的一般规则是,每次经过一个点时,油箱里烧的油一定是此点向前600m(加满油最大 距离)范围内最便宜的加油站里的油
具体算法:
600m范围内(向前开),本加油站油价最低:
加满,开到次低的加油站(可能有余油)接着使用该策略加 此时判断剩余距离是否低于 600,若低于600则直接走到。
本加油站油价非最低:(找个离自己最近的油价比自己低的站,不一定是600m范围内最低的)
加到恰好能开到离自己最近的比自己便宜的那个加油站,之后再用相同策略 此处千万不能因为剩余距离<MaxD而直接走到终点,走到终点的最后一个加油站一 定是范围内最便宜的一个,也即最终输出总money的代码只能是在上面当前站最低 的分支下,否则会有下面错误样例
直到终点也在600m范围时加到能开到终点即可(一定在终点600m向前最便宜的一个加油站加过油)
自己分析得其实不错,就是快到终点时激动了,只要到达终点600m范围内任何一个加油站就直接加到终点了。。导致错误,其他都正确
易错样例
53 5995 17 95
7.00 863
3.00 1355
6.00 1131
1.00 5851
6.00 2011
8.00 4186
1.00 1650
3.00 3649
4.00 4358
7.00 1462
9.00 1267
4.00 5454
4.00 4644
4.00 2266
9.00 5129
8.00 4213
10.00 48
1.00 3095
9.00 4868
1.00 175
2.00 3274
4.00 3676
4.00 2929
3.00 3561
10.00 968
3.00 1663
5.00 2220
3.00 928
2.00 1384
9.00 2274
9.00 4634
2.00 28
6.00 3786
5.00 402
6.00 1333
9.00 5589
3.00 5938
8.00 415
2.00 239
9.00 3966
10.00 498
6.00 1289
8.00 4889
9.00 2710
2.00 2284
8.00 4225
6.00 1820
1.00 3039
3.00 5308
3.00 1954
6.00 2725
5.00 794
1.00 5835
2.00 546
6.00 1679
1.00 1918
4.00 788
8.00 147
7.00 4709
4.00 4013
2.00 3800
4.00 3378
9.00 1204
9.00 1205
2.00 1885
5.00 1071
4.00 4882
4.00 2305
9.00 2840
7.00 3639
1.00 2598
10.00 4693
7.00 105
7.00 259
8.00 1528
10.00 1869
2.00 2410
7.00 821
7.00 3746
7.00 5107
2.00 1979
1.00 5686
2.00 5667
2.00 69
10.00 2430
3.00 5893
5.00 5956
6.00 1787
4.00 3551
7.00 278
9.00 5602
8.00 327
2.00 1012
7.00 2650
7.00 0
//596.88
原始代码:
#include<iostream>
#include<algorithm>
using namespace std;
struct station {
double price, dis;
}sta[550];
bool compare(station a, station b) {
return a.dis<b.dis;
}
int main() {
//freopen("in.txt", "r", stdin);
double C, D, Davg;//安全起见 都定义为double
int N;
cin >> C >> D >> Davg >> N;
for (int i = 0;i<N;i++) {
cin >> sta[i].price >> sta[i].dis;
}
sort(sta, sta + N, compare);
double Maxd = C*Davg;//单次最远距离
if (sta[0].dis != 0) {
printf("The maximum travel distance = 0.00");
return 0;
}
//for (int i = 0;i < N;i++) {
// cout << i<<": "<<sta[i].price << " " << sta[i].dis << endl;
//}
double nowCan = 0;//当前余油能行驶的距离
double money = 0;//当前花费的总金额
for (int i = 0;i<N;i++) {
if (i == N - 1&&D-sta[i].dis>Maxd) {//都开到头了 还是到不了
printf("The maximum travel distance = %.2f", sta[i].dis + Maxd);
}
//开不到下一站
if (sta[i + 1].dis - sta[i].dis>Maxd) {
printf("The maximum travel distance = %.2f", sta[i].dis + Maxd);
return 0;
}
/*if (i == 84) {
cout << nowCan << endl;
}*/
int min = i;
//Maxd范围内找个比自己便宜的 离自己最近的 加油站 //而不是找最便宜的 距离最近是第一要素
for (int j = i + 1;j<N&&sta[j].dis - sta[i].dis <= Maxd;j++) {
if (sta[j].price < sta[i].price) {//是i不是min 一个看似简单错误 卡了好久
min = j;
break;
}
}
if (min == i) {//当前站最短
if (sta[i].dis + Maxd >= D) {//当前站最便宜 且终点在范围内
//直接加到终点站
money += sta[i].price*(D - sta[i].dis - nowCan) / Davg;
printf("%.2f", money);
return 0;
}
//加满
money += sta[i].price*(Maxd - nowCan) / Davg;
nowCan = Maxd;
int next = i + 1;//下一站肯定能行驶到 否则早return了
for (int j = i + 2;j<N&&sta[j].dis - sta[i].dis <= Maxd;j++) {//Maxd范围内找个次便宜的加油站
if (sta[j].price<sta[next].price) next = j;
}
//开到次便宜的站
nowCan -= (sta[next].dis - sta[i].dis); //有余油
i = next - 1;//i++就到next了
}
else {//min站最短(非当前站)
//终点在范围内
//此处即使终点在范围内也不能立刻开到 还要不断地找最短站。也即min==i时 此时自己才是Maxd范围内的最便宜 才能大胆走到
//加油到恰好能开到最短站
money += sta[i].price*(sta[min].dis - sta[i].dis - nowCan) / Davg;
//开到最短站
nowCan = 0;
i = min - 1;//i++就到next了
}
}
return 0;
}
整理后:
#include<iostream>
#include<algorithm>
using namespace std;
struct station {
double price, dis;
}sta[550];
bool compare(station a, station b) {return a.dis<b.dis;}
int main() {
//freopen("in.txt", "r", stdin);
double C, D, Davg;//安全起见 都定义为double
int N;
cin >> C >> D >> Davg >> N;
for (int i = 0;i<N;i++) {
cin >> sta[i].price >> sta[i].dis;
}
sort(sta, sta + N, compare);
double Maxd = C*Davg;//单次最远距离
if (sta[0].dis != 0) {
printf("The maximum travel distance = 0.00");
return 0;
}
double nowCan = 0,money = 0;//当前余油能行驶的距离 当前花费的总金额
for (int i = 0;i<N;i++) {
if (i == N - 1&&D-sta[i].dis>Maxd) {//都开到头了 还是到不了
printf("The maximum travel distance = %.2f", sta[i].dis + Maxd);
}
if (sta[i + 1].dis - sta[i].dis>Maxd) {//开不到下一站
printf("The maximum travel distance = %.2f", sta[i].dis + Maxd);
return 0;
}
int min = i;
//Maxd范围内找个比自己便宜的 离自己最近的 加油站 //而不是找最便宜的 距离最近是第一要素
for (int j = i + 1;j<N&&sta[j].dis - sta[i].dis <= Maxd;j++) {
if (sta[j].price < sta[i].price) {//是i不是min 一个看似简单错误 卡了好久
min = j;
break;
}
}
if (min == i) {//当前站最短
if (sta[i].dis + Maxd >= D) {//当前站最便宜 且终点在范围内
money += sta[i].price*(D - sta[i].dis - nowCan) / Davg;//直接加到终点站
printf("%.2f", money);
return 0;
}
money += sta[i].price*(Maxd - nowCan) / Davg;//加满
nowCan = Maxd;
int next = i + 1;//下一站肯定能行驶到 否则早return了
for (int j = i + 2;j<N&&sta[j].dis - sta[i].dis <= Maxd;j++) {//Maxd范围内找个次便宜的加油站
if (sta[j].price<sta[next].price) next = j;
}
nowCan -= (sta[next].dis - sta[i].dis); 开到次便宜的站有余油
i = next - 1;//i++就到next了
}
else {//min站最短(非当前站)
money += sta[i].price*(sta[min].dis - sta[i].dis - nowCan) / Davg;
nowCan = 0;//开到最短站
i = min - 1;//i++就到next了
}
}
return 0;
}