旅行家的预算 --- 贪心

传送门

题目描述

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

分析

本题即可贪心也可分治,以下为贪心的思路。

1.无解:若存在满油情况下,到不了下一个站,则无解
2.到了站p后,在可满油可到的范围内找费用最小的加油站k,若k的费用比p小,则将油量加到恰好到达k,否则在p处将油加满,到达k站
3.可用单调队列实现:假设到每个站都将油加满,并记录到该站时最多能加多少油(费用也先算上,到后面再减去),用单调队列选择费用最小的
  对于从p->p + 1,期间的需要的油由前面若干个便宜的加油站提供。
  将p站的加油费用加入单调队列(对于队列末端费用比它大的,踢出队列,顺便减去多加的费用)
  注意到达终点是将单调队列清空,并减去其中多加的费用

代码

#include <cstdio>
#include <cstdlib>
#include <deque>

#define IL inline
#define open(s) freopen(s".in", "r", stdin); freopen(s".out", "w", stdout);
#define close fclose(stdin); fclose(stdout);

using namespace std;

IL int read()
{
	int sum = 0;
	int k = 1;
	char c = getchar();
	for(;'0' > c || c > '9'; c = getchar())
	if(c == '-') k = -1;
	for(;'0' <= c && c <= '9'; c = getchar())
		sum = sum * 10 + c - '0';
	return sum * k;
}

const int maxn = 10000 + 1;

struct node
{
	double c;
	double p;
	IL node(double c_ = 0, double p_ = 0)
	{
		c = c_; p = p_;
	}
};

int n;
double cap, cd;
double ans;
deque<node> Q;
double dis[maxn], price[maxn];

int main()
{
	open("traveller")
	
	scanf("%lf %lf %lf %lf", &dis[0], &cap, &cd, &price[0]); n = read() + 1;
	dis[n] = dis[0]; dis[0] = 0;
	
	for(int i = 1; i <= n; ++i)
	{
		if(i < n) scanf("%lf %lf", &dis[i], &price[i]);
		if(dis[i] - dis[i - 1] > cap * cd) { ans = -1; break;}
	}
	
	if(!ans)
	{
		double c1 = cap, c;
		ans += price[0] * cap;
		Q.push_back(node(cap , price[0]));
		for(int i = 1; i <= n; ++i)
		{
			c = (dis[i] - dis[i - 1]) / cd;
			c1 -= c;
			for(;!Q.empty() && c;)
			{
				if(Q.front().c > c)
				{
					Q.front().c -= c;
					break;
				}else
				{
					c -= Q.front().c;
					Q.pop_front();
				}
			}
			
			if(i == n)
			{
				for(;!Q.empty(); Q.pop_back()) ans -= Q.back().p * Q.back().c;
				break;
			}
			
			for(;!Q.empty() && Q.back().p >= price[i];)
			{
				ans -= Q.back().p * Q.back().c;
				c1 -= Q.back().c;
				Q.pop_back();
			}
			
			ans += price[i] * (cap - c1);
			Q.push_back(node(cap - c1, price[i]));
			c1 = cap;
		}
	}
	if(ans == -1) printf("No Solution\n"); else printf("%.2lf\n", ans);
	
	close
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值