1033. To Fill or Not to Fill (25)

1.这道题目比较有趣,给出了加油站的位置和每个站的油价,求最小耗费,如果不能到达终点,则求能走的最远距离

2.思路:

1)采用一个油箱数组的概念,实则是一个vector,当成队列使用,这个vector记录了加了的油的价格,油的容量,通过这些油走过的长度和耗费;

2)每到一个站,计算从上一站达到这个站所需要的油needGas

3)从油箱数组容量不为0的油中开始遍历,直接完全满足needGas的要求,同时计算油箱数组中被使用到的油的耗费和走的距离。

4)遍历完油箱数组后,如果needGas不为0,那么油箱数组的总油量不够用,直接计算油箱数组走的总距离并输出答案

5)如果needGas为0,那么对比油箱数组剩余油(油的容量不为0)的价格,如果比当前站高,则更新为当前站的价格,

其实际意义是:到了当前的加油站,油箱里面还有油(这些油可加也可不加,都能使车到达当前站点),这些油的价格比当前加油站要高(那么之前就没必要加油,直接在当前站点加满),那么在之前就不加油了,在这个站点家满cMax的油量,记录价格,进入下一次循环即可。

6)把终点作为最后一个站,油的价格为0.


AC的代码如下,有详细解释:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;
/*
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

50 1300 12 2
7.10 0
7.00 600

50 0 12 2
7.10 0
7.00 600

50 0 12 0

50 13000 12 2
7.10 0
7.00 600
*/
struct stationNode{
	float price;
	int position;
	stationNode() :price(0), position(0){};
};
struct gasNode{
	float price;//价格
	float cap;//容量
	float cost;//总价格
	float dist;
	gasNode() :price(0), cap(0), cost(0),dist(0){};
	gasNode(float p,float c) :price(p), cap(c), cost(0),dist(0){};
};
bool cmp(const stationNode&a, const stationNode&b)
{
	return a.position < b.position;
}
int main(void)
{
	int cMax, target, dAvg, n;
	cin >> cMax >> target >> dAvg >> n;
	n++;//把终点也作为一个站
	vector<stationNode> sta(n);
	for (int i = 0; i < n - 1; i++)
	{//初始化
		cin >> sta[i].price >> sta[i].position;
	}
	sta.back().position = target;//设置终点的距离
	sort(sta.begin(), sta.end(), cmp);//按照站的位置进行排序
	vector<gasNode> gas(0);//油箱数组
	int gasIndex = 0;//记录当前用到哪个油箱数组的油
	float totalGas = 0;
	if (0 >= sta[0].position)
	{//把第一个站加进去,包含价格信息和加了多少油
		gas.push_back(gasNode(sta[0].price, cMax));
		totalGas = cMax;
		//now += cMax*dAvg;
	}
	for (int now = 1; now < n; now++)
	{
		//needGas表示从i-1站到i站需要多少油
		float needGas = (sta[now].position - sta[now - 1].position) *1.0 / dAvg;

		//把油箱里的油减去需要用的油,计算得到油箱还剩多少油
		totalGas -= needGas;
		//在这里可以直接判断totalGas是否小于0,小于0表示油箱不够油跑下去,但是由于题目还需要求最长距离,所以这里不作处理,统计完邮箱所有的油再进行处理


		//遍历邮箱数组,利用gasIndex做开始位,减少时间复杂度
		for (int j = gasIndex; j < gas.size(); j++)
		{
			if (gas[j].cap > needGas)
			{//当前vector的油能够满足需求
				gas[j].cap -= needGas;//减去需要用的油,得到剩余的油
				gas[j].cost += needGas*gas[j].price;//计算这个vector的油已经耗费了多少钱
				gas[j].dist += needGas*dAvg;//计算这个vector的油走了多长的路
				gasIndex = j;//下次直接从这个vector计算油量
				needGas = 0;
				break;
			}
			else if (gas[j].cap < needGas)
			{//如果当前vector的油量不足
				gas[j].cost += gas[j].cap*gas[j].price;//计算这个vector的油耗费了多少钱
				gas[j].dist += gas[j].cap*dAvg;//计算这个vector的油走了多长的路
				needGas -= gas[j].cap;//除去这个vector的油,还需要多少油
				gasIndex = j;
			}
			else
			{//刚好等于需要的油,由于使用了float,基本不会出现这种needGas等于0的情况
				gas[j].cost += gas[j].cap*gas[j].price;//计算这个vector的油耗费了多少钱
				gas[j].dist += gas[j].cap*dAvg;//计算这个vector的油走了多长的路
				needGas -= gas[j].cap;//needGas为0
				gasIndex = j + 1;//直接指向下个vector
				break;
			}
		}

		if (needGas > 0)
		{//当前油箱的总油量不能走到当前地点
			float totalDist = 0;
			//统计走了多少路
			for (int j = 0; j < gas.size(); j++)
				totalDist += gas[j].dist;

			printf("The maximum travel distance = %.2f", totalDist);
			return 0;
		}

		//能够到当前地点
		for (int j = gasIndex; j < gas.size(); j++)
		{//遍历邮箱里面存在的油,如果价格比当前油站要高,那么就更新价格
		//实际的意义相当于:到了当前的站还有油剩(这些油可加可不加),且之前加的油价格比当前油站要高(这些油没必要在之前加),那么在之前就不加油了,全换成到这个站才加油
			if (gas[j].price>sta[now].price)
				gas[j].price = sta[now].price;
		}
		//把油补充满
		gas.push_back(gasNode(sta[now].price, cMax - totalGas));
		totalGas = cMax;
	}

	//计算总价格
	float totalCost = 0;
	for (int i = 0; i < gas.size(); i++)
	{
		totalCost += gas[i].cost;
	}
	printf("%.2f", totalCost);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值