2013寒假练习 1005:穿越沙漠

地址:http://acm.bit.edu.cn/mod/programming/view.php?id=656

趣题,所以把题面也搬过来

穿越沙漠
时间限制: 1秒  内存限制: 64M
Problem Description

一辆吉普车来到 x 公里宽的沙漠边沿 A 点,吉普车的耗油量为 1 升 / 公里,总装油量为 500 升。通常,吉普车必须用自身油箱中的油在沙漠中设置若干个临时储油 点,才能穿越沙漠的。假设在沙漠边沿 A 点有充足的汽油可供使用,那么吉普车从 A 点穿过这片沙漠到达终点 B ,至少要耗多少升油。请编写一个程序,计算最少的 耗油量(精确到小数点后 3 位)。 
( 1 )假设吉普车在沙漠中行进时不发生故障; 
( 2 )吉普车在沙漠边沿 A 点到终点 B 的直线距离为 x ≧ 500 公里 ( 即沙漠宽度 ) ;

Input

输入的第一行含一个正整数 k ,表示测试例的个数。后面紧接着 k 行,每行对应一个测试例,包含一个正整数 x ,表示从 A 点到 B 点的距离( 1<=x<=2000 )。

Output

每个测试例对应一行输出,包含一个数,表示最少的油耗量(精确到小数点以后 3 位)。

Sample Input

2

500

1000

Sample Output

500.000

3836.497


想好久想不出来。。智商捉鸡啊。。一开始觉得是递推、DP之类的怎么搞都搞不出来。然后看了各种题解,还是没法严谨地证明,不过大概意思懂了。

比较数学化的推理参看http://blog.csdn.net/zhangwei1120112119/article/details/8501270

比较形象化的解释:

x<=500  那么无须在中途扔油,耗油量就等于x,在边界x=500处,耗油500;

500<x<=500+500/3 此时为了最后一次能跑完超过500的距离,必须在终点前500距离扔油(*),如图所示。那么总共所需油为3a+500 也就是在这一阶段,每增加1公里路程,需要多用3升油(2升用来往返扔油,1升是多走1公里所用的油)。但是当a这一段多出来的距离大于500/3时,3a>500,也就是从起点去扔油的所需的油都已经超过了500,那么就需要再多扔一次油。所以边界条件为X=500+500/3时,此时耗油1000.

500+500/3<x<=500+500/3+500/5    此时需要扔两次油,位置如图。为何第一个点要扔3a呢?因为接下来第二次扔油的一个来回多走了2a,最后穿过沙漠的那一次多走了a,所以要扔3a的油。此时耗油为5a+1000,即每增加1公里路程,需要多用5升油。当a大于500/5时,第一个点扔油所用油5a又超过了500,所以x=500+500/3+500/5即为边界条件,此时耗油1500.

接下来每多走1公里须多耗7升油,持续到7a>500;

再接下来每多走1公里须多耗9升油,持续到9a>500;

。。以此类推

如样例中x=1000  即500+500/3+500/5+。。。+500/13+22.4331 所以耗油500*7+22.4331*15=3836.497

*注:大于500距离无法完全利用油,小于500距离不划算

(但如何证明这样的走法是最优的呢?)

#include<iostream>
using namespace std;
int main()
{
	int	t,i;
	double sum,x;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%lf",&x);
		for(sum=0,i=1;x-500.0/i>=0;i+=2)
		{
			sum+=500,x-=500.0/i;
		}
		printf("%.3lf\n",sum+x*i);
	}
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值