算法笔记练习 4.4 贪心 问题 B: 出租车费
题目
题目描述
某市出租车计价规则如下:起步4公里10元,即使你的行程没超过4公里;接下来的4公里,每公里2元;之后每公里2.4元。行程的最后一段即使不到1公里,也当作1公里计费。
一个乘客可以根据行程公里数合理安排坐车方式来使自己的打车费最小。
例如,整个行程为16公里,乘客应该将行程分成长度相同的两部分,每部分花费18元,总共花费36元。如果坐出租车一次走完全程要花费37.2元。
现在给你整个行程的公里数,请你计算坐出租车的最小花费。
输入
输入包含多组测试数据。每组输入一个正整数n(n<10000000),表示整个行程的公里数。
当n=0时,输入结束。
输出
对于每组输入,输出最小花费。如果需要的话,保留一位小数。
样例输入
3
9
16
0
样例输出
10
20.4
36
思路
贪心
根据题意,先画表直观感受一下每公里价格随单次打车路程的变化:
路程 | 总价 | 每公里价格 |
---|---|---|
1 | 10 | 10.00 |
2 | 10 | 5.00 |
3 | 10 | 3.33 |
4 | 10 | 2.50 |
5 | 12 | 2.40 |
6 | 14 | 2.33 |
7 | 16 | 2.29 |
8 | 18 | 2.25 |
对于一次打 8 公里以上的情况,因为大于 8 公里的部分每公里要 2.4 元,可以预见每公里价格从 8 公里开始会逐渐上升,直到渐近 2.4 元。
根据以上分析 8 公里的每公里价格是最低的,所以应尽量以 8 公里一次来打车。下面根据总路程length
的情况作分类讨论:
- 如果
length <= 8
,那么一次打车一定比多次打车便宜; - 如果
length > 8
,先尽量以 8 公里一次的方式走完尽可能多的路程,即打length / 8
次,剩余length % 8
公里的路程有两种处理方式:
a. 多加一次打车,打length % 8
公里;
b. 与最后一次打车合并为一次打车,即最后一次打8 + length % 8
公里。
观察上面的表,当length % 8 <= 4
的时候,方案 a 会亏,因为方案 b 多出来的路程每公里只需要 2.4 元。
细节:
一开始自作聪明地用了%g
输出ans
,本以为这样就不用判断带不带小数部分了,事实上%g
在数据大的时候会以科学计数法(即%e
)输出。
代码
#include <stdio.h>
int main(){
int n;
// 表示单独一次打车 1~7 公里所需的车费
long long costs[7] = {10, 10, 10, 10, 12, 14, 16};
long long length;
double ans;
while (scanf("%d", &length) != EOF){
ans = 0;
if (length == 0) continue;
if (length >= 8){
ans += (double)(length / 8) * 18.0;
length %= 8;
if (length <= 4)
ans += (double)length * 2.4;
else
ans += (double)costs[length-1];
} else {
ans = costs[length-1];
}
if (ans - (long long)ans)
printf("%.1lf\n", ans);
else
printf("%.0lf\n", ans);
}
return 0;
}