洛谷 P1016 [NOIP1999 提高组] 旅行家的预算【贪心】

news2025/3/10 20:47:51

原题链接:https://www.luogu.com.cn/problem/P1016

题目描述

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

输入格式

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

接下来有 N 行。

第 i+1 行,两个数字,油站 i 离出发点的距离 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

说明/提示

N≤6,其余数字 ≤500。

NOIP1999 普及组第三题、提高组第三题

解题思路:

这个题目我觉得是一个比较好的贪心题,这个题目可能思维不是那么的难,但是一写起来代码细节特别的多,一些边界哨兵的合理设置就能减少一些特判,就能减少代码量。

首先考虑一下简化版,首先我们认为汽车油箱的容量是无限的,那么这个题目就简单多了,每个位置城市肯定都是从当前位置前面所有的城市中油价最低的城市过来,这样就能保证总花费最少,但是这个题目难就难在汽车的容量是有限制的,这就相当于把这个题目加了一个限制,就是当前位置城市只能从当前位置城市前面一定区间内的城市转移过来,下面我们考虑一种贪心策略。

(1)在每一个位置,考虑在加满油时,当前位置城市后面可以到达的城市中找第一个比当前位置城市油价低的城市,如果找到了,将油加到刚好能够到达这个城市即可。

那么为什么加到能刚好到达下一个到达的城市就是最优的,因为我们找到的下一个城市油价更低,在当前位置多加一些油,不如到下一个城市在加,因为下一个城市花费更低。

(2)考虑在加满时,如果在当前位置城市后面可以到达的城市里面找不到油价更低的城市,那么我们需要在能够到达的城市里面找到一个油价最低的城市,并且此时我们应该加满油,然后到达这个油价最低的城市,那么此时又有一个疑问了,那么此时为什么要加满油呢。

此时为什么加满油最优?因为下一个要到达的城市油价比当前位置城市油价高,所以在当前位置加满油是更优的,那么为什么要加满呢,我就不能少加一点吗?,事实证明这是不可以的,我来画个图描述一下:

根据上述图中分析,可以知道这种情况加满油肯定是更优的。

(3)第三种情况就是,如果当前城市不是目标城市,并且就算加满油,但是连最近的城市都到不了,那么说明无法到达目标城市,表示无解。

细节分析见代码处。

时间复杂度:O(n),因为每一个位置只会枚举一次。

空间复杂度:O(n)。

cpp代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 10;

double dist, cap, travel_dist, oil_cost; // dist表示俩座城市的距离,cap表示汽车油箱的容量,travel_dist表示每升油能形式的距离,oil_cost表示起点每升油的价格
int n;                                   // n表示起点和终点之间有n座加油站
double d[N], oil[N];                     // d[i]表示第i座加油站距离起点的距离,oil[i]表示第i座加油站每升油的价格

int main()
{
    cin >> dist >> cap >> travel_dist >> oil_cost >> n;
    for (int i = 1; i <= n; i++)
        cin >> d[i] >> oil[i];
    d[0] = 0, oil[0] = oil_cost;  //起点哨兵记得标记好
    d[n + 1] = dist, oil[n + 1] = 0;  //目标城市为n+1,距离为dist,油价设为0,表示如果可以在前面分析的操作中可以直接到达目标城市,那么就直接到达

    double total_cost = 0;  //记录总的花费
    int curr_pos = 0;  //记录当前所在位置,初始时在位置0表示起始城市
    bool Solution = true;  //表示是否无法到达目标城市,为true表示可以到达目标城市,为false表示不能到达目标城市
    double remain_oil = 0;  //表示当前油箱剩余油量
    while (curr_pos < n + 1)  //只要没有到达目标城市n+1,那么就需要寻找下一个需要前往的城市
    {
        int next_pos = curr_pos + 1, min_pos = next_pos;
        if ((d[next_pos] - d[curr_pos]) / travel_dist - cap > 1e-4) //如果连最近的一个城市都无法到达,说明无解
        {
            Solution = false;
            break;
        }
        double min_cost = oil[next_pos]; //记录当前位置城市后面能到达的最小油价城市
        bool ok = true;
        for (int i = next_pos; i <= n + 1; i++)
        {
            double liter = (d[i] - d[curr_pos]) / travel_dist;
            if (liter - cap > 1e-4)  //当前位置在油箱加满油时都无法到达,后面的城市就都无法到达了,此时还没有找到第一个比当前位置城市油价低的城市,把ok设为false,表示后面的可以到达的城市没有比当前位置城市油价低的
            {
                ok = false;
                break;
            }
            if (min_cost - oil[i] > 1e-4)  //处理当前位置城市后面可以到达的城市里面油价最低的那个城市
            {
                min_pos = i;  //记录位置
                min_cost = oil[i];  //记录最小油价
            }
            if (oil[curr_pos] - oil[i] > 1e-4)
            {
                next_pos = i;   //当前位置城市后面可以到达的城市里面,找到了第一个比当前位置城市油价低的城市
                break;
            }
        }

        if (!ok)  //在当前位置城市后面可以到达的城市里面没有找到比当前位置城市油价低的城市
        {
            next_pos = min_pos;  //那么就应该去往后面可以到的城市里面油价最低的那个城市
        }
        double distance = d[next_pos] - d[curr_pos];
        double need_liter = distance / travel_dist;  //记录到达后面需要到达的位置需要花费多少升油
        if (!ok)  //在当前位置城市后面可以到达的城市中没有找到比当前位置油价更低的城市
        {
            double need_oil = cap - remain_oil;  //根据上面的分析,这种情况应该加满油,油箱中前面还剩余了remain_oil升油,那么需要加cap-remain_oil升油
            total_cost += need_oil * oil[curr_pos];  //在当前位置城市需要加need_oil升油,所以需要花费need_oil*oil[curr_pos]的钱
            remain_oil = cap - need_liter;  //油箱加满油之后,到达下一个城市需要花费need_liter升油,所以到达下一个位置next_pos之后,油箱中应该还剩下cap-need_liter升油
        }
        else //找到了
        {
            double need_oil = need_liter - remain_oil;  //找到了就只需要将油箱中的油加到刚好能到达下一个需要到达的城市即可
            total_cost += need_oil * oil[curr_pos];  //需要加need_oil升油,所以花费为need_oil*oil[curr_pos]
            remain_oil = 0;  //到达下一个需要到的城市之后,此时油箱中剩余的油量为0
        }

        curr_pos = next_pos;  //到达下一个需要到达的城市
    }
    if (!Solution)  //无解
    {
        cout << "No Solution";
    }
    else
    {
        printf("%.2lf", total_cost);  //输出最小花费
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1461323.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计网day5

六 传输层 6.1 传输层概述 6.2 UDP协议 6.3 TCP协议 TCP连接管理&#xff1a; TCP可靠传输&#xff1a; TCP拥塞控制&#xff1a;

unity学习(32)——跳转到角色选择界面(父子类问题)

新问题 应该是两个脚本之间缺少继承关系 its children 解决起来很简单&#xff0c;把ResceneScript也绑到canvas上就可以了 。 此时&#xff0c;在账号密码正确的情况下&#xff0c;是可以完成场景切换。 对应的代码如下&#xff1a; TMP_Text d GameObject.FindWithTag(&…

【问题解决】删除node节点后如何把node节点重新加入

环境明细 docker版本&#xff1a; 25.0.3kubeadm 版本&#xff1a;v1.25.0 1 在master节点删除node节点 [rootk8s-master ~]# kubectl delete nodes k8s-node-02 node "k8s-node-02" deleted [rootk8s-master ~]# kubectl get nodes -o wide NAME STAT…

基于 GTSAM 的因子图简单实例

Title: 基于 GTSAM 的因子图简单实例 文章目录 I. 引言II. GTSAM 的安装与配置III. 基于 GTSAM 的因子图实例的 C 实现1. C 源码2. CMakeLists.txt 脚本3. 数值结果 IV. 基于 GTSAM 的因子图实例的 Python 实现1. Python 源码2. 数值结果3. 可视化结果 V. 总结 关联博文: 因子图…

day2:信号与槽

思维导图 使用手动连接&#xff0c;将登录框中的取消按钮使用t4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断u界面上输入的账号是否为"123",密码是否为"…

springboot集成JWT实现token权限认证

vuespringboot登录与注册功能的实现 注&#xff1a;对于JWT的学习&#xff0c;首先要完成注册和登录的功能&#xff0c;本篇博客是基于上述博客的进阶学习&#xff0c;代码页也是在原有的基础上进行扩展 ①在pom.xml添加依赖 <!-- JWT --> <dependency><grou…

【Linux】git操作 - gitee

1.使用 git 命令行 安装 git yum install git 2.使用gitee 注册账户 工作台 - Gitee.com 进入gitee&#xff0c;根据提示注册并登录 新建仓库 仓库名称仓库简介初始换仓库 3.Linux-git操作 进入仓库&#xff0c;选择“克隆/下载” 复制下面的两行命令进行git配置 然后将仓库clo…

Vue3引用第三方模块报错Could not find a declaration file for module ***.

在引用第三方的组件时候报错如下 原因是&#xff1a;该组件可能不是.ts文件而是.js文件 解决方案&#xff1a; 1.在Src的目录下面新建一个文件为shims-vue.d.ts的文件 2.文件内容为 declare module xxx&#xff0c;xxx就是你报错的模块 例如我这样 declare module vue3-pu…

【C语言】中的位操作符和移位操作符,原码反码补码以及进制之间的转换

欢迎大家来到c语言知识小课堂&#xff0c;今天的知识点是操作符和进制 目录 一、进制之间的转化1、什么是二进制&#xff0c;八进制&#xff0c;十进制&#xff0c;十六进制2、进制之间的转化其他进制转化为十进制十进制转化为二进制二进制转化为八进制八进制转化为二进制二进…

2023年最新阿里云服务器价格表(配置价格+磁盘+带宽)

2024年阿里云服务器租用价格表更新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年、ECS u1实例2核4G、5M固定带宽、80G ESSD Entry盘优惠价格199元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元、2核4G4M带宽轻量服务器一年165元12个月、2核4G服…

P2957 [USACO09OCT] Barn Echoes G

P2957 [USACO09OCT] Barn Echoes G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P2957 题目分析 对于求单个字符串的哈希值相当于求前缀和&#xff0c;而求单个字符串的子串的哈希值则相当于求其区间和&#xff1b; 那么只需求两个…

fail-safe机制与fail-fast机制分别有什么作用

fail-safe和fail-fast&#xff0c;是多线程并发操作集合时的一种失败处理机制。 Fail-fast&#xff1a;表示快速失败&#xff0c;在集合遍历过程中&#xff0c;一旦发现容器中的数据被修改了&#xff0c;会立刻抛出ConcurrentModificationException异常&#xff0c;从而导致遍…

Selenium基于Python web自动化测试框架 -- PO

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

代码随想录第二十一天 701.二叉搜索树中的插入操作 108.将有序数组转换为二叉搜索树

701.二叉搜索树中的插入操作 题目描述 给定二叉搜索树&#xff08;BST&#xff09;的根节点 root 和要插入树中的值 value &#xff0c;将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 &#xff0c;新值和原始二叉搜索树中的任意节点值都不同。 注意&a…

CF1468J Road Reform 题解

CF1468J Road Reform 题解 link CF1468J Road Reform 题面翻译 给定一个有 n n n 个节点&#xff0c; m m m 条无向带权边的图&#xff0c;和一个参数 k k k&#xff0c;第 i i i 条边权值为 s i s_i si​。 现在你要保留这个图中的 n − 1 n-1 n−1 条边使得这个图变…

306_C++_QT_创建多个tag页面,使用QMdiArea容器控件,每个页面都是一个新的表格[或者其他]页面

程序目的是可以打开多个styles文件(int后缀文件),且是tag样式的(就是可以切多个页面出来,并且能够单独关闭);其中读取ini文件,将其插入到表格中的操作,也是比较复杂的,因为需要保持RGB字符串和前面的说明字符串对齐 ini文件举例: [MainMenu] Foreground\Selected=&…

63-JQuery语法,选择器,事件,方法,遍历循环each

1.一个JS库,用js封装很多的方法放到一个文件里面,直接拿了用就可以 文件名带min是压缩过的不带min是没压缩过的 2.JQuery语法 通过选取HTML元素,并对选取的元素执行某些操作 基础语法:$(selector).action() <!-- 需要把JQuery文件先引入才能用 --><script src…

Project_Euler-06 题解

Project_Euler-06 题解 题目描述 两个公式 等差数列求和公式 i i i项&#xff1a; a i a_{i} ai​ 项数&#xff1a; n n n 公差&#xff1a; d d d 和&#xff1a; S n S_{n} Sn​ a n a 1 ( n − 1 ) d S n n ( a 1 a n ) 2 a_{n} a_{1} (n - 1)d\\ S_{n} \frac{n(a_…

L1-047 装睡-java

输入格式&#xff1a; 输入在第一行给出一个正整数N&#xff08;≤10&#xff09;。随后N行&#xff0c;每行给出一个人的名字&#xff08;仅由英文字母组成的、长度不超过3个字符的串&#xff09;、其呼吸频率和脉搏&#xff08;均为不超过100的正整数&#xff09;。 输出格…

百度地图海量点方案趟坑记录(百度地图GL版 + MapVGL + vue3 + ts)

核心需求描述 不同层级有不同的海量图标展示底层海量图标需要展示文字拖动、放大缩小都需要重新请求数据并展示固定地图中心点&#xff08;拖动、放大缩小&#xff0c;中心点始终在地图中心&#xff09; 示例图片&#xff1a;&#xff08;某些图片涉及公司数据&#xff0c;就未…