我的PAT-ADVANCED代码仓:https://github.com/617076674/PAT-ADVANCED
原题链接:
PAT-ADVANCED1033:https://pintia.cn/problem-sets/994805342720868352/problems/994805458722734080
Data Structures and Algorithms7-32:https://pintia.cn/problem-sets/16/problems/694
题目描述:
PAT-ADVANCED1033、Data Structures and Algorithms7-32:
题目翻译:
1033 加油或不加油
有了高速公路,从杭州开车到任何其他城市都很方便。 但由于汽车的油箱容量有限,我们不得不在途中找到加油站。 不同的加油站可能会给不同的价格。 你需要设计最便宜的路线。
输入格式:
每个输入文件包含一个测试用例。对每个测试用例,第一行包含4个正整数:Cmax(<= 100),代表油箱的最大容量;D(<= 30000),代表杭州到目的地城市间的距离;Davg(<= 20),代表1单位汽油所能行驶的距离;以及N(<= 500),代表加油站总数。接下来N行。每行给出一对非负数字:Pi,代表单位汽油的价格,以及Di(<= D),代表该加油站离杭州的距离,i = 1, ..., N。一行中的所有数字由一个空格分隔。
输出格式:
对每个测试用例,输出最便宜的价格,精确到小数点后2位。假设油箱的初始状态是空的。如果不可能到达目的地,输出“The maximum travel distance = X”,其中X表示汽车能够行驶的最大距离,精确到小数点后两位。
输入样例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
输出样例1:
749.17
输入样例2:
50 1300 12 2
7.10 0
7.00 600
输出样例2:
The maximum travel distance = 1200.00
知识点:贪心算法
思路:贪心算法
首先对加油站进行按距离升序排序。
总体原则:在每个站点所能到达的下一个加油站内优先寻找第一个价格更低或相等的加油站,如果没有找到这样的加油站,则取能到达的下一个加油站内价格最低的加油站作为下一个加油站。
(1)如果D == 0,即目的地就是杭州,直接输出“0.00”即可,并return 0,结束main函数。
(2)如果第一个加油站离杭州的距离不为0,由于我们油箱初始为空,因此直接输出“The maximum travel distance = 0.00”,并return 0,结束main函数。
(3)如果不是上述两种情况,我们需要进入下述循环过程:
a:如果当前加油站是最后一个加油站,
a-1:如果当前加油站加满油也到达不了目的地,直接输出能到达的最大距离。
a-2:如果当前加油站加满油可以到达目的地,
a-2-1:如果当前汽车里剩余油的量足够支持汽车到达目的地,则不需要再加油。
a-2-2:如果当前汽车里剩余油的量不够汽车到达目的地,我们需要加油使得汽车油量刚好能支持汽车到达目的地,并增加价格。
做完上述讨论后,都需要break出循环。
b:如果在当前加油站加满油也到达不了下一个加油站,
b-1:如果在当前加油站加满油还到达不了目的地,直接输出能到达的最大距离。
b-2:如果在当前加油站加满油能到达目的地,则和a-2中的情况一样对价格进行增加。
做完上述讨论后,都需要break出循环。
c:在当前加油站加满油能到达的下一个加油站里寻找价格比当前加油站更低或相同的加油站,
c-1:如果在能到达的下一个加油站里能找到价格比当前加油站更低或相同的加油站,那么我们的下一个加油站就应该选取第一个比当前加油站价格更低或相同的加油站。
c-1-1:但是如果目的地在当前加油站和我们选定的下一个加油站之间,那么只需加能到达目的地的油量即可,如果剩余油量足够,甚至不需要加油,同时break跳出循环。
c-1-2:更新到达下一个加油站时的剩余油量值。
c-2:如果在能到达的下一个加油站里无法找到价格比当前加油站更低或相同的加油站,那么我们的下一个加油站就应该选取能到达的加油站里价格最低的加油站。
c-2-1:但是如果目的地在我们当前加油站能够加满油到达的范围内,我们直接到达目的地即可,同时break跳出循环。
c-2-2:由于当前加油站的价格比下一个加油站的价格要低,我们选择在当前加油站加满油。
c-2-3:更新到达下一个加油站时的剩余油量值。
时间复杂度是O(NlogN)。空间复杂度是O(N)。
C++代码:
#include<iostream>
#include<algorithm>
using namespace std;
struct station {
double price;
double distance;
};
bool cmp(station s1, station s2);
int main() {
double Cmax, D, Davg;
int N;
cin >> Cmax >> D >> Davg >> N;
station stations[N + 1];
for(int i = 1; i < N + 1; i++) {
scanf("%lf %lf", &stations[i].price, &stations[i].distance);
}
sort(stations + 1, stations + N + 1, cmp);
if(D == 0) { //如果杭州距离目的地的距离D是0,我们不需要任何花费就已经到达了目的地
printf("0.00");
return 0;
}
if(stations[1].distance != 0) { //如果第1号加油站的距离离杭州大于0,由于一开始油箱为空,我们不可能到达目的地
printf("The maximum travel distance = 0.00\n");
return 0;
}
double cost = 0.0; //代表花费总额
double maxLen = Cmax * Davg; //满油状态下能行进的最大距离
int now = 1; //一开始我们处在1号加油站的位置
int next; //下一个加油站
double nowOil = 0.0; //当前我们的汽车有多少油
while(true) {
//如果当前加油站已经是最后一个加油站了
if(now == N) {
if(stations[now].distance + maxLen < D) {
//在最后一个加油站加满油也到达不了目的地D
printf("The maximum travel distance = %.2lf\n", stations[now].distance + maxLen);
} else {
//在最后一个加油站加满油可以到达目的地D,但我们没必要加满油
if(nowOil < (D - stations[now].distance) / Davg) {
cost += stations[now].price * ((D - stations[now].distance) / Davg - nowOil);
}
printf("%.2lf\n", cost);
}
break;
}
int min = now + 1;
int i = now + 1;
//如果在now加满油到达不了下一个加油站
if(stations[i].distance > stations[now].distance + maxLen) {
//如果在now站加满油也到达不了目的地
if(D > stations[now].distance + maxLen) {
printf("The maximum travel distance = %.2lf\n", stations[now].distance + maxLen);
} else {
//如果在now站加满油到达不了下一个加油站但是可以到达目的地
if(nowOil < (D - stations[now].distance) / Davg) {
cost += stations[now].price * ((D - stations[now].distance) / Davg - nowOil);
}
printf("%.2lf\n", cost);
}
break;
}
for(; stations[i].distance - stations[now].distance <= maxLen && i < N + 1; i++) { //循环a
//在now能到达的下一个加油站里寻找价格最低的那个加油站编号
if(stations[i].price < stations[min].price) {
min = i;
}
//在now位置能到达的下一个加油站里寻找价格比now加油站更低或价格相同的加油站
if(stations[i].price <= stations[now].price) {
next = i;
break;
}
}
//如果在能到达的下一个加油站里无法找到价格比当前加油站更低或相同的加油站,那么我们的下一个加油站就选取能到达的加油站里价格最低的加油站
if(i == N + 1 || stations[i].distance - stations[now].distance > maxLen) { //取的循环a中循环终止的相反条件
//如果在now站加满油就能够到达目的地了
if(stations[now].distance + maxLen >= D) {
if(nowOil < (D - stations[now].distance) / Davg) {
cost += stations[now].price * ((D - stations[now].distance) / Davg - nowOil);
}
printf("%.2lf\n", cost);
break;
}
//我们在now能到达的下一个加油站里寻找价格最低的那个加油站
next = min;
//加满油
cost += stations[now].price * (Cmax - nowOil);
//到达next时,油箱里的油不为空
nowOil = Cmax - (stations[next].distance - stations[now].distance) / Davg;
} else {
//如果在now能到达的下一个加油站里能找到比now加油站价格更低的加油站
//如果距离D在加油站now和next之间,那么只需加能到达目的地D的油即可
if(stations[next].distance >= D) {
if(nowOil < (D - stations[now].distance) / Davg) {
cost += stations[now].price * ((D - stations[now].distance) / Davg - nowOil);
}
printf("%.2lf\n", cost);
break;
}
//在now加油站只需加能到达next加油站的油即可
if(nowOil < (stations[next].distance - stations[now].distance) / Davg) {
cost += stations[now].price * ((stations[next].distance - stations[now].distance) / Davg - nowOil);
//到达next时,油箱里的油为空
nowOil = 0.0;
} else {
//到达next时,油箱里的油为原有的油减去路上花费的油
nowOil -= (stations[next].distance - stations[now].distance) / Davg;
}
}
now = next;
}
return 0;
}
bool cmp(station s1, station s2) {
return s1.distance < s2.distance;
}
C++解题报告: