• 洛谷千题详解 | P1016 [NOIP1999 提高组] 旅行家的预算【C++、Java、Python语言】


    博主主页:Yu·仙笙

    专栏地址:洛谷千题详解

    目录

    题目描述

    输入格式

    输出格式

    输入输出样例

     解析:

    C++源码:

    Java源码:

    Python源码:


    ------------------------------------------------------------------------------------------------------------------------------- 

     ------------------------------------------------------------------------------------------------------------------------------- 

    题目描述

    一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的)。给定两个城市之间的距离 D_1D1​、汽车油箱的容量 CC(以升为单位)、每升汽油能行驶的距离 D_2D2​、出发点每升汽油价格PP和沿途油站数 NN(NN 可以为零),油站 ii 离出发点的距离 D_iDi​、每升汽油价格 P_iPi​(i=1,2,…,Ni=1,2,…,N)。计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出 No Solution

    输入格式

    第一行,D1​,C,D2​,P,N。

    接下来有 N 行。

    第 i+1 行,两个数字,油站 ii 离出发点的距离 Di​ 和每升汽油价格 Pi​。

    输出格式

    所需最小费用,计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出 No Solution

    输入输出样例

    输入 #1

    275.6 11.9 27.4 2.8 2
    102.0 2.9
    220.0 2.2
    

    输出 #1

    26.95

     ------------------------------------------------------------------------------------------------------------------------------- 

     解析:

    这道题目应该算是妥妥的贪心+模拟吧……

    算法原理如下:

    1.枚举途中经过的加油站,每经过一个加油站,计算一次花费;

    2.在一个加油站所需要加的油,就是能够支持它到达下一个油价比它低的加油站的量;

    3.如果在这个加油站即使加满油,都不能到达一个比它油价低的加油站,就把油箱加满,前往能够到达的加油站中油价最低的那个;

    4.如果在这个加油站即使加满油,都不能到达任意一个加油站,也不能到达终点城市,说明无解;

    **第三点:为什么要加满油?**因为这样可以减少在下一个加油站(价格更贵)所需要加的油量。

     ------------------------------------------------------------------------------------------------------------------------------- 

    C++源码:

    1. #include
    2. using namespace std;
    3. #define maxn 100000
    4. #define db double
    5. #define INF 9999999
    6. int n;
    7. db D1, D2, C, P, res, ans, maxx;
    8. struct node
    9. {
    10. db co, dis;
    11. bool friend operator <(const node& a, const node& b)
    12. { return a.dis < b.dis; }
    13. }pl[maxn];
    14. int Solve(int now)
    15. {
    16. int flag = INF; db d = pl[now].dis;
    17. for(int i = now + 1; i <= n && pl[i].dis - d <= maxx; i ++)
    18. {
    19. if(pl[i].co < pl[now].co)
    20. {
    21. ans += ((pl[i].dis - d - res) / D2) * pl[now].co;
    22. res = 0; return i;
    23. }
    24. if(flag == INF || pl[i].co < pl[flag].co) flag = i;
    25. }
    26. if(D1 - pl[now].dis <= maxx)
    27. {
    28. ans += ((D1 - pl[now].dis - res) / D2) * pl[now].co;
    29. return INF;
    30. }
    31. if(flag == INF) { printf("No Solution\n"); return -1; }
    32. else
    33. {
    34. ans += C * pl[now].co; res += (maxx - (pl[flag].dis - d));
    35. return flag;
    36. }
    37. }
    38. int main()
    39. {
    40. scanf("%lf%lf%lf%lf%d", &D1, &C, &D2, &P, &n);
    41. pl[0].dis = 0, pl[0].co = P;
    42. for(int i = 1; i <= n; i ++)
    43. scanf("%lf%lf", &pl[i].dis, &pl[i].co);
    44. sort(pl, pl + n + 1);
    45. maxx = C * D2;
    46. int k = 0, t;
    47. do
    48. {
    49. t = Solve(k), k = t;
    50. if(t == -1) return 0;
    51. }while(t != INF);
    52. printf("%.2lf", ans);
    53. return 0;
    54. }

     ------------------------------------------------------------------------------------------------------------------------------- 

    Java源码:

    1. import java.util.*;
    2. public class 旅行家的预算 {
    3. public static void main(String[] args)
    4. {
    5. Scanner sc=new Scanner(System.in);
    6. double D1=sc.nextDouble();//两个城市之间的距离
    7. double C=sc.nextDouble();//汽车油箱的容量
    8. double D2=sc.nextDouble();//每升油能行驶的距离
    9. double P=sc.nextDouble();//出发点的油价
    10. int N=sc.nextInt();//沿途油站数
    11. double[] Pi=new double[N+2];//每个站点的油价
    12. double[] D=new double[N+2];//离出发点的距离
    13. double MaxDistance=D2*C;
    14. //初始化距离和油价数组,将起点与终点也加入其中
    15. D[0]=0;Pi[0]=P;
    16. D[N+1]=D1;Pi[N+1]=0;
    17. for(int i=1;i<=N;i++) {
    18. D[i]=sc.nextDouble();
    19. Pi[i]=sc.nextDouble();
    20. }
    21. double fee=0;
    22. double remain=0;
    23. //无解的情况
    24. for(int i=0;i<=N;i++)
    25. if(D[i+1]-D[i]>MaxDistance) {
    26. System.out.println("No Solution");
    27. return ;
    28. }
    29. //有解,开始遍历每一个站点
    30. int i=0;
    31. while(i<=N)
    32. {
    33. int j;
    34. for(j=i+1;j<=N+1;j++)
    35. {
    36. if (D[j]-D[i]>MaxDistance)
    37. {
    38. j-=1;//最大行驶距离无法到达j,因此最大到达j-1站点
    39. break;
    40. }
    41. if(Pi[j]<=Pi[i])
    42. break;//找到下一个更便宜的加油站
    43. }
    44. if(Pi[j]<=Pi[i]) //找到了下一个更便宜的加油站
    45. {
    46. fee+=((D[j]-D[i])/D2-remain)*Pi[i];//更新费用
    47. remain=0;//更新到达下一个加油站后的剩余油量
    48. }
    49. else//没有找到加满油
    50. {
    51. fee+=(C-remain)*Pi[i];
    52. remain=C-(D[j]-D[i])/D2;
    53. }
    54. i=j;//前往下一个加油站,滴滴滴!
    55. }
    56. System.out.println(String.format("%.2f", fee));
    57. }
    58. }

     ------------------------------------------------------------------------------------------------------------------------------- 

    Python源码

    1. d1, c, d2, p, N = [float(x) for x in input().split()]
    2. ls = list()
    3. ls.append([0, p])
    4. for i in range(int(N)):
    5. ls.append([float(x) for x in input().split()])
    6. ls.append([d1, float("inf")])
    7. # 思路:让每一段的路费最便宜,找到start-end两点间最便宜的油站,买它的油走到终点。若剩下的油不能到达该油站,则找start到该油站之间最便宜的。
    8. # start,end是当前位置和要去的终点, leftover是剩下的油,返回这种情况下的最少花销consume
    9. def MinConsume(start, end, leftover):
    10. global ls, c, p, d2
    11. Consume = 0
    12. # 能直接到终点
    13. if start == end:
    14. return Consume
    15. elif ls[end][0]-ls[start][0] <= leftover*d2:
    16. return Consume
    17. # 到不了下一站
    18. elif ls[start+1][0]-ls[start][0] > c*d2:
    19. return -1*float("inf")
    20. # 不能直接到终点
    21. else:
    22. # 寻找剩下路径第一个最便宜的站
    23. cheapp = float("inf")
    24. cheapindex = -1
    25. for i in range(start, end):
    26. if cheapp > ls[i][1]:
    27. cheapindex = i
    28. cheapp = ls[i][1]
    29. #考虑当前站到最便宜站的耗费
    30. # 剩下的油能到最便宜的站
    31. if leftover*d2 >= ls[cheapindex][0]-ls[start][0]:
    32. leftover -= (ls[cheapindex][0]-ls[start][0])/d2
    33. else:
    34. # 剩下的油不能到,则找这两者之间的最便宜的站再加油直到到达那个站,到达那个站后油量为0
    35. Consume += MinConsume(start, cheapindex, leftover)
    36. leftover = 0
    37. # 考虑最便宜站到终点的耗费
    38. # 在最便宜的站加油能到终点
    39. if c >= (ls[end][0]-ls[cheapindex][0])/d2:
    40. Consume += ((ls[end][0]-ls[cheapindex][0])/d2-leftover)*cheapp
    41. # 在该站加满油不能到终点,则到该站加满再走到下一个站,可能no solution
    42. else:
    43. Consume += (c-leftover)*ls[cheapindex][1]
    44. #走到最便宜的下一站剩的油
    45. leftover = c-(ls[cheapindex+1][0]-ls[cheapindex][0])/d2
    46. # 最便宜的站能到其下一站
    47. if leftover >=0:
    48. Consume += MinConsume(cheapindex+1, end, leftover)
    49. else:
    50. Consume = -1*float("inf")
    51. return Consume
    52. Consume = MinConsume(0, len(ls)-1, 0)
    53. if Consume >= 0:
    54. Consume = round(Consume, 2)
    55. print("{:.2f}".format(Consume))
    56. else:
    57. print("No Solution")

     ------------------------------------------------------------------------------------------------------------------------------- 

  • 相关阅读:
    投影仪有哪些模块组成?
    Springboot-MyBatisPlue入门
    关于竞赛,CSDN还有很长的路要走
    Windows11重置提示找不到恢复环境怎么解决?
    简单工厂、工厂方法 、抽象工厂模式之间的联系
    Android面试整理之SQLite数据库——sql语句和常用函数(一)
    网站收集软件-免费网站收集软件
    IDEA的下载和安装
    PaddleX数据标注与Halcon数据标注与转换
    C#演示单例模式
  • 原文地址:https://blog.csdn.net/djfihhfs/article/details/127743469