您的位置:首页 > 其它

2013寒假练习 1005:穿越沙漠

2013-02-01 14:34 260 查看
地址: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之类的怎么搞都搞不出来。然后看了各种题解,还是没法严谨地证明,不过大概意思懂了。

比较数学化的推理参看/article/10284949.html
比较形象化的解释:
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: