暑期刷题系列之PAT A1033

本文解析PAT甲级1033题,利用贪心算法规划最经济路线。通过设定三条准则,确保在有限油量下以最低成本完成行程,或输出最大可行距离。

  今天做了一道贪心算法的题,个人认为比较典型,且我在解题过程中逻辑也比较清晰,所以想写篇博客记录下自己的想法。

  这是PAT甲级的一道题(PAT 甲级1033)。

  以下是题目描述:


1033 To Fill or Not to Fill (25)(25 分)

With highways available, driving a car from Hangzhou to any other city is easy. But since the tank capacity of a car is limited, we have to find gas stations on the way from time to time. Different gas station may give different price. You are asked to carefully design the cheapest route to go.

Input Specification:

Each input file contains one test case. For each case, the first line contains 4 positive numbers: C~max~ (<= 100), the maximum capacity of the tank; D (<=30000), the distance between Hangzhou and the destination city; D~avg~ (<=20), the average distance per unit gas that the car can run; and N (<= 500), the total number of gas stations. Then N lines follow, each contains a pair of non-negative numbers: P~i~, the unit gas price, and D~i~ (<=D), the distance between this station and Hangzhou, for i=1,...N. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print the cheapest price in a line, accurate up to 2 decimal places. It is assumed that the tank is empty at the beginning. If it is impossible to reach the destination, print "The maximum travel distance = X" where X is the maximum possible distance the car can run, accurate up to 2 decimal places.

Sample Input 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

Sample Output 1:

749.17

Sample Input 2:

50 1300 12 2
7.10 0
7.00 600

Sample Output 2:

The maximum travel distance = 1200.00

题目大意

就是开车经过一段路程,已知起点与终点并且知道其距离D,还知道油箱的最大油量Cmax,单位汽油可以行驶的距离Davg,路途中会有N个加油站,每个加油站的油价都不同,如果到达该加油站则可以买油,最多加满油箱。需要你规划出汽车到达终点的花费最小的方法,如果不能到达终点,则输出汽车所能到达的最短距离。汽车开始在起点处,油箱油量为0.

个人解法:

其实这题一看就知道是个贪心算法的题。

我们需要做的其实就是在能力范围内同样的距离花最少的钱。

分析:

一、假如你此处在加油站k,那么在油箱加满的情况下所能到达的所有加油站中,如果有油的单价比当前油站价格低的话,令该油站编号为dest,那么我们肯定得选择用当前油站最少的油来达到dest,也就是到达dest后油箱剩余油量为0,并且dest是第一个油价比当前油站k小的油站。为什么呢?其实可以用反证法,若是到达dest后有剩余油量,那么这些油箱我们肯定在后面的路程中是要花掉的,但是我们已经到达了一个更便宜的加油站dest,dest的油价更低,所以我们为什么不用dest的油来代替上一个油站假的油呢。

二、假如你此处在加油站k,但是在你能到达的范围内没有更便宜加油站,那该怎么办呢?那么我们就要选择所能到达的加油站里油价最便宜的那个,设编号为mink,然后在k加满油再到达mink,为什么这样选择呢?其实我们可以把mink看成一个过渡的加油站,因为我们希望到达mink后,这时我们所能到达的范围内的加油站可能会更多,希望这些加油站里有比当前加油站油价比较低的油站dest,这样才能在同样的钱发挥最大的价值。

注:有个特殊情况需要注意,就是可到达的范围内没有更便宜的加油站,但是可以直接到达终点,这时我们要对终点进行判别。

其实说的这么多就是三条准则:

1、选择所能到达的范围内第一个合适的油站(即该油站价格比当前油站价格低),并且在当前油站加油到刚好能达到该合适的油站。

2、若可到达的范围内无适合油站,则将油加满,然后到达可选择的油站中油价最低的那个,但须注意一种特殊情况,也就是对能否到达终点进行判断(下面有具体代码)。

3、若可到达的范围无油站,则此时判别能否到达终点。

下面是代码

#include <cstdio>
#include <algorithm>
#define MAXN 505
#define INF 100000000
using namespace std;

double cmax, davg, dis;
int N;

struct station {
	double price;
	double distance;
}A[MAXN];

bool cmp(station a,station b){
	return a.distance < b.distance;
}

int main() {
	double range, pos = 0;   //pos为当前位置的距离
	double tprice;         //目标油站油价
	double tgas, pgas;    //tgas为需要加多少油,pgas为油箱原有多少油
	double res = 0;       //最终结果
	int k;                  //当前油站   
	bool pflag = false;     //pflag表示可到达的范围内有价格较低的油站
	bool dflag = false;     //dflag表示可到达的范围内有油站
	scanf("%lf %lf %lf %d", &cmax, &dis, &davg, &N);
	for (int i = 0; i < N; i++) {
		scanf("%lf %lf", &A[i].price, &A[i].distance);
	}
	sort(A, A + N, cmp);
	if (A[0].distance != 0) {         //若最近的加油站不在零点,注意该特殊情况
		printf("The maximum travel distance = 0.00");
		return 0;
	}
	range = cmax * davg;
	pgas = 0;
	tprice = A[0].price;
	k = 0;   //当前油站编号
	double min = INF;  //最低的油价
	int mink; //最小的油站的编号
	while (pos < dis) {
		if (k + 1 < N) {
			if (A[k + 1].distance <= (pos + range)) {                //如果可到达的范围内有油站,则更新dflag
				dflag = true;
			}
		}
		if (dflag) {           //第一大类情况,可到达的最大范围内有油站
			for (int i = k + 1; i < N; i++) {
				if (A[i].distance <= (pos + range)) {
					dflag = true;
					if (A[i].price < tprice) {                       //第一种情况:可到达的范围内有油站比当前油站油价价格低的油站      
						tgas = (A[i].distance - pos) / davg - pgas;   //将油加到刚好可以到达该油站
						res += tgas * A[k].price;
						k = i;
						pos = A[k].distance;
						tprice = A[k].price;
						pgas = 0;
						pflag = true;
						break;
					}
				}
			}
			if (!pflag) {                         //第二种情况:可到达的范围内没有价格较低的油站,但有油站可以到达
				if ((pos + range) >= dis) {       //如果有油站但可直接到达终点的话,对特殊情况进行判别,如果存在则可以直接返回
					tgas = (dis - pos) / davg - pgas;
					res += tgas * A[k].price;
					printf("%.2lf", res);
					return 0;
				}
				//需要选择可到达的范围内油价最低的油站
				for (int i = k + 1; i < N; i++) {
					if (A[i].distance <= (pos + range)) {
						if (A[i].price <= min) {          //注意是小于等于
							min = A[i].price;
							mink = i;
						}
					}
				}
				tgas = cmax - pgas;                      //将油加满
				res += tgas * A[k].price;
				//更新变量的值
				pgas = cmax - (A[mink].distance - pos) / davg;   //更新油量
				k = mink;
				pos = A[k].distance;
				tprice = A[k].price;
			}
		}
		if (!dflag) {                     //第三种情况,没有范围内可到的油站
			if ((pos + range) >= dis) {
				tgas = (dis - pos) / davg - pgas;
				res += tgas * A[k].price;
				printf("%.2lf", res);
				return 0;
			}
			else {                       //不能到达终点
				pos += range;
				printf("The maximum travel distance = %.2lf", pos);
				return 0;
			}
		}
		pflag = false;
		dflag = false;
		min = INF;
	}
	return 0;
}

以上就是我的解法,并且AC了,其实代码冗余的地方还是有的,并且这题还有个更简单的方法,比如将终点当成一个油价为0,距离为全部距离的加油站,这样解法可以更简单一点,大家可以思考一下。

这是我第一次写技术博客,实属心血来潮,文中难免有表达不清晰、不到位的地方,还请大家见谅。

 

 

内容概要:本文研究了基于DPWMA调制与正负序分离的ANPC三电平并网逆变器前馈控制策略,旨在解决传统三电平逆变器存在的谐波含量高、电网不平衡工况适应性差及动态响应速度不足等问。通过采用有源中点箝位(ANPC)三电平逆变器拓扑,结合双极性倍频脉宽调制(DPWMA)、正负序分离锁相技术和电网电压前馈控制,构建了一套一体化的高性能并网控制体系。该体系不仅优化了逆变器的开关动作机制,改善了输出电压电流的谐波特性,而且通过精确的相位同步和扰动补偿,显著提高了系统的动态响应能力和抗扰性能。仿真结果显示,所提出的控制策略能有效降低并网谐波含量,提升锁相精度与系统动态稳定性,确保在复杂电网工况下的高质量稳定并网。 适合人群:具备一定电力电子基础知识和仿真技能的研发人员,尤其是从事新能源发电、储能系统、柔性输电等领域研究的专业人士。 使用场景及目标:①研究和开发高性能并网逆变器,特别是针对大功率、高电能质量要求的应用场景;②探索如何通过先进的调制和控制策略来提高并网逆变器对电网扰动的适应性和响应速度;③为相关领域的学术研究和技术开发提供理论依据和实践指导。 阅读建议:建议读者结合实际的仿真软件(如MATLAB/Simulink)进行实践操作,以便更好地理解和掌握文中提到的各种控制策略的具体实现方法。同时,鼓励读者关注最新的研究成果和发展趋势,不断深化对该领域的认识。
摘要 在全球生态环境问日益严峻、公众环保参与意愿持续提升的背景下,传统环保志愿者招募与管理模式存在信息传播零散、供需对接不畅、管理效率低下等痛点,制约了环保公益事业的规模化发展。为解决上述问,响应生态保护数字化发展需求,本课设计实现“守望自然”环保志愿者招募与管理网站,通过数字化手段打通环保组织与志愿者的服务链路,对推动环保公益规范化、高效化发展具有重要的现实意义与实践价值。 该网站采用B/S架构与前后端分离模式开发,前端基于Vue架构建组件化响应式界面;后端以Java为开发语言,采用Spring Boot框架搭建应用,搭配MyBatis作为持久层框架,数据库选用MySQL并遵循第三范式设计7个以上核心数据表。系统涵盖用户与管理员两大核心角色,实现了闭环式环保志愿服务功能:用户端支持注册登录、个人信息管理、活动查询报名、环保知识学习、社区互动、问反馈及客服咨询等功能,满足用户全流程参与需求;管理员端具备用户管理、用户审核、招募与活动信息发布管理、环保知识内容管理、问反馈处理、证书模板管理、多维度数据可视化分析及社区内容监管等功能,全面支撑环保组织运营管理。开发过程中集成了Token身份认证、MD5密码加密、ECharts数据可视化等关键技术,融入活动智能推荐、数据驱动决策等创新设计,确保系统功能完备性与实用性。 经功能测试、性能测试及安全测试验证,系统运行稳定可靠,具有良好的易用性、安全性和可扩展性,能够高效满足环保组织的用户招募管理需求与用户的多元化参与需求,有效降低环保组织运营成本,提升用户参与体验,为环保理念传播与公益事业发展提供有力的数字化支撑。 关键词:环保志愿者;招募管理系统;Spring Boot;Vue;数据可视化
特等奖标准成品论文(Word无水印纯净版) 硬核结构:全文包含完整的摘要、问重述与分析、模型假设、符号说明、模型建立与求解、灵敏度分析及结论。 即插即用:排版严格遵循官方规范,逻辑严密。拿到手即可作为绝佳的高分参考模板,稍作替换与个性化润色即可极速完稿,彻底解决写论文难的痛点。 双源硬核解代码(Python与MATLAB双版本) 拒绝假代码:提供底层逻辑清晰、模块化设计的全套可运行源码。 全流程覆盖:涵盖从前期数据清洗预处理,到中期核心数学模型训练,再到后期启发式算法寻优。 傻瓜式运行:代码自带详尽的逐行中文注释,并支持一键生成高质量结果可视化图表,编程小白也能轻松复现与二次开发。 全量数据与结果展示表 所有中间处理数据、模型输出参数以及最终结论,均已精细整理成高质量表格。直观呈现性能评估指标与多模型对比分析,可直接作为论文正文或附件使用,极大提升学术说服力。 独家硬核思路解析 深入浅出剖析出人意图,详细拆解每一小问的数学本质与底层逻辑,让你不仅知其然更知其所以然。 【四大核心产品优势】 高效实用:所有代码与论文均经过严格测试,确保结果精准无误、完全可复现,省去熬夜试错的时间。 全栈覆盖:从思路分析到跑出结果,再到写出高质量论文,提供一站式全流程资料矩阵。 排版辅助:资料内提供专业的论文排版一键转换工具与官方标准模板,告别格式调整的繁琐。 持续迭代:网盘直发,开赛后资料库将持续滚动更新,所有用户均可免费同步获取最新包。 【适用人群】 想要打破建模瓶颈的参赛队长与主攻手;急需高质量底层代码的编程小白;目标直指特等奖需要高分模板对标的精英团队。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值