zoukankan      html  css  js  c++  java
  • 旅行家的预算 题解

    通往题目的大门

    题目描述

    一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的)。给定两个城市之间的距离D1、汽车油箱的容量C(以升为单位)、每升汽油能行驶的距离D2、出发点每升汽油价格P和沿途油站数N(0<=N<=100),油站i离出发点的距离Di、每升汽油价格Pi(i=1,2,……N)。计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出“No solution”。

    • 输入格式 第1行:5个空格分开的数据,分别表示D1 C D2 P N 第2..N+1行:每行3个空格分开的数据,分别表示油站号i, 该油站距出发点的距离Di,该油站每升汽油的价格Pi
    • 输出格式 第1行:一个数据,表示最少费用。

    样例输入

    275.6 11.9 27.4 2.8 2    
    1 102.0 2.9    
    2 220.0 2.2
    

    样例输出

    26.95
    

    分析

    这道题还是有难度的,在与一位大巨佬两个小时的语音通话后,总结出了AC这道题的方法,如下:主要是没看懂GM的题解
    首先,这是一道贪心题:花最少的钱走完全程。现在,我们先来点简单的
    改变一下题目,把油箱的容量改为无限,则贪心策略显而易见:

    step1.

    起点时一定要加油的,每升要用P元。假设中途有三个加油站,且你不想在中途加油,那么你的其实就是每一段都用的P价格的油

    start--P--a[1]--P--a[2]--P--a[3]--P--end  
    

    如果我告诉你第二个加油站每升只要 P-1 元,你还会傻傻的用上面这个方案吗?我猜不会,你可以一开始就加刚好能到第二个加油站的油,后半程就可以换成 P-1 元的油了,如下图

    start--P--a[1]--P--a[2]--(P - 1)--a[3]--(P - 1)--end 
    

    是不是赚了?我们把它一推广,就可以得到

    step2.

    在每个加油站加油只需加到能到达后面油价最低(且比它的油价还低)的加油站即可,若找不到这种加油站,恭喜你,可以准备直达了,中途不用换油,记:在第 i 个加油站加油用了 cost[i] 元,则有

    int mi = INT_MAX, v = i;
    for(int j = i + 1; j <= n; i++) {    
    	if(a[j].p < mi && a[j].p < a[i].p) {     
    		mi = a[j].p;      
    		v = j    
    	}
    }
    if(v == i) cost[i] = (d1 - a[i].d) / d2 * a[i].p;
    else cost[i] = (a[v].d - a[i].d) / d2 * a[i].p;
    

    不一定对哈,毕竟没认真实现过


    前面的那么多都是引入,开始正题
    引入已经说的很清楚了,在这道题的正解中,我们只是多加入了一个判断无解:当在一个加油站加满油还不能到达下一个加油站时,旅行失败。

    还有就是因为油箱容量有上限,所有我们还需要看一下当前油箱省的油最远能到哪一个加油站,确定选最小值的距离范围
    我们还考虑了一下,距离远近顺序的问题,就是一号加油站可能在二号加油站后面,所以先有一次排序。但最后发现,数据中没有这一情况。

    根据思路不难得出

    AC代码

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int MAXN = 105;
    struct data { // 结构体 
        int i;
        double di, pi;
    //	油站 i 离出发点的距离 Di, 每升汽油价格 Pi
    } a[MAXN];
    bool cmp(data x, data y) { // sort cmp 函数 
    	return x.di < y.di;
    }
    
    int main() {
    	double d1, c, d2, p;
    	int n;	
        scanf ("%lf %lf %lf %lf %d", &d1, &c, &d2, &p, &n); 
    //	给定两个城市之间的距离 D1, 汽车油箱的容量 C, 每升汽油能行驶的距离 D2, 出发点每升汽油价格 P和沿途油站数 N 
        a[0].di = 0, a[0].pi = p;
        for (int i = 1; i <= n; i++) {
            scanf ("%d %lf %lf", &a[i].i, &a[i].di, &a[i].pi);
            a[i].di /= d2;
        }
        a[n + 1].di = d1 / d2; 
        n += 2;
        sort(a, a + n, cmp);
        for (int i = 1; i < n; i++) 
            if (a[i].di - a[i - 1].di > c) { // 判断无解 
                printf("No solution");
                return 0;
            }
    
        double rest = 0, cost;
    
        for (int i = 0; i < n; i++) {
            int min_pos = i; // 价格最低的加油站的位置 
            double min_val = a[i].pi; // 价格最低的加油站的价格 
            int j, k;
    //  j 剩余油量能到达的最远的加油站 
    //  k j + 1 到 n - 1 中第一个比 minpos 便宜的点 
            for (j = i + 1; j < n && a[j].di - a[i].di <= rest; j++)
                if (min_val < a[j].pi)
                    min_val = a[j].pi, min_pos = j;
    //	求出价格最低的加油站的相关信息 
            for (k = j; k < n; k++)
                if (a[k].pi < min_val)
                    break;
            if (k == n) // 判断能否到终点 
                k = n - 1;
    
            rest -= (a[min_pos].di - a[i].di); 
            double end = (a[k].di - a[min_pos].di); 
    //  rest 第一部分的路程
    //  end  第二部分的路程 
            if (end <= c) {  // 能直接到达 K
                cost += (end - rest) * a[min_pos].pi; // 加油 
                if (k == n - 1)
                    break;
                else
                    i = k - 1, rest = 0; // 更新 
            } 
    		else {  // 否则加满油
                cost += (c - rest) * a[min_pos].pi;
                i = min_pos;  
                rest = c; 
                rest -= a[i + 1].di - a[i].di;
            }
        }
        printf("%.2lf
    ", cost);
        return 0;
    }
    
  • 相关阅读:
    strcpy,memset,memcpy三者之间的根本区别
    最便捷、最强大、速度最快的C++序列化框架
    C++读写二进制文件
    boost binary 序列化
    febird.dataio和boost.serialization性能对比
    Boost文本序列化和二进制序列化的效率比较
    Boost文本序列化和二进制序列化的效率比较
    c++的vector赋值方法汇总
    OCP-1Z0-051-V9.02-36题
    遍历list或map时删除元素(较巧妙)
  • 原文地址:https://www.cnblogs.com/Chain-Forward-Star/p/13868040.html
Copyright © 2011-2022 走看看