旅行家的预算

问题描述

洛谷P1016

题目分析

1、若在前一个油站把油加满都不能到下一个油站,则无法到达目的地。否则,一定可以到达目的地。
2、因为在任何一个油站都可以把油箱加满,所以当我们到达加油站i时,油站i之前的油站不再考虑,只需要考虑此时油箱里的油 和 油站i后面的油站。
3、也是因为在任何一个油站都可以把油箱加满,所以当我们到达加油站i时,只需要考虑从油站i要去往哪个油站,而不用考虑再去往哪个油站等其他后续问题。
4、假设油箱容量无上限,从现在的位置,我们希望跑到一个比现在位置油价更便宜的油站。用更便宜的油价加油继续往下跑。而且加油前,油箱里的价格更贵的油恰好用完。
5、在油箱容量有限的前提下,如果能跑到一个比现在位置油价更便宜的油站,那就跑过去。油价相等的地方也行,相当于扩充邮箱容量。如果能跑到的油站都比现在的油价贵,假设目的地无限远,那就在当前油站加满油,跑到能跑到的油价最低的油站。因为目的地无限远,所以加满油也跑不完,所以不用考虑会剩下油。
6、将目的地也看做一个油站,油价无穷小。那么上一条就不会出现剩油的情况。因为在到达目的地前的最后一次加油,不会出现“能跑到的油站都比现在的油价贵”的情况。
7、倘若出现多个油站油价相同,那么如果出发点油价<到达点油价,则去尽可能远的那个。如果出发点油价>到达点油价,则去尽可能近的那个。

思路

1、对除了目的地的每个油站判断,若在该油站加满都不能到下一个油站,结束。
2、若在当前油站加满油,能到达油价比它低的油站,则去油价比它低的最近的油站。
3、即使在当前油站加满油,也不能到达油价比它低的油站,则去它能到的油价最低的油站,若这样的油站有多个,则去最远的那个。

代码

#include<stdio.h>

const double eps=1e-8;

int n;//油站个数 
double m,C,d,p[9],dis[8];
// m总距离  C油箱容量  d每升汽油能行驶的距离 
//p[]每个位置的油价  dis[]每个位置距离出发点的距离 

int i,j;
int now,to;//now当期在哪个油站  to要去的油站 
double need,sum,have;
//need从now到to需要的油量   sum总花费  have邮箱剩余油量 

double abs(double a) //计算绝对值函数 
{
	if(a>0) return a;
	if(a<0) return -a;
}

void read()
{
	scanf("%lf%lf%lf%lf%d",&m,&C,&d,&p[0],&n);
	for(i=1;i<=n;++i) scanf("%lf%lf",&dis[i],&p[i]);
	dis[n+1]=m;
	p[n+1]=-1; //目的地看做第n+1个油站 
	p[n+2]=501; //留一个油价无限大的位置,后面计算油价最小的油站时作初始值
	//因为题目说数据范围<=500,所以501相当于一个极大值。油价不为负,-1相当于一个极小值 
}

int no_solution() //判断无解 
{
	for(i=0;i<=n;++i)
		if(C*d<dis[i+1]-dis[i])
		{
			printf("No Solution");
			return 1;
		}
	return 0;
}

void find()
{
	j=n+2;
	for(i=now+1;i<=n+1;++i)
	{
		if((dis[i]-dis[now])/d>C) break; //超出能跑的范围 
		if(p[i]<p[now] || abs(p[i]-p[now])<eps) //找到一个比当前油站油价便宜或相等的油站 
		{
			j=i;
			break;
		}
		if(p[i]<p[j] || abs(p[i]-p[j])<eps) j=i; //找油价最低的油站 
	}	
	to=j;
}

void price()
{
	need=(dis[to]-dis[now])/d;
	if(p[to]<p[now] || abs(p[to]-p[now])<eps) //出发点油价<=到达点,恰好跑到到达点,油箱不剩油 
	{
		sum+=(need-have)*p[now];
		have=0;
	}
	else //出发点油价>到达点,油箱加满 
	{
		sum+=(C-have)*p[now];
		have=C-need;
	}
	now=to; 
}
	
int main()
{	
	read();
	if(no_solution()) return 0;
	while(now<=n)
	{
		find();//找下一个要去的油站 
		price();//计算这一段的价格 
	}
	printf("%.2lf",sum);
	return 0;
}			
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值