第一次训练赛-I-穿越沙漠

I - 穿越沙漠

FZU - 1076

 

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

Input

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

Output

每个测试例对应一行输出,包含一个数,表示最少的油耗量。

Sample Input

2
500
1000

Sample Output

500.000
3836.497

借助了一下百度大佬的思路才写的(变笨了变笨了)

主要思路就是不停的将油量“无限”的(最优算法则是“刚好够用”的)加油站向前迁移,并且因为第一次迁移加油站所需要移动的油最多(因为走越久消耗越多),因此往返的次数最多,所以需要取整时候应该缩短第一次迁移的距离,并且计算的时候从后往前计算。

比如对于501km:

最后一个加油站(包括车上剩的和此前存的)油量:500L,在1m处

则前一个加油站直接可以是我们的无限油站,第一次在1km处放1L油,往返共耗油2L,第二次再来到1km处,车上剩499L油,刚好加满驶向终点

那么假设路程非常非常长:

最后一个加油站油量:500L,在离终点500km处不解释

倒数第二个加油站应当做到“效率”最大:

设这两个加油站距离为x,往返次数为a(先往返a次,然后直接开过去),则每次往返运油(500-2*x),耗油2*x,最后一趟(只去不回)为(500-x),耗油x,为了计算效率,列出下列等式。

a = (500-(500-x)) / (500-2*x)   (往返次数为:往返运油总量/每次运油量,并且是非负整数)(实际上只有最后500km路a为0)

(a*2*x+x) / x尽量小   (单位迁移距离的耗油量,应该尽量小,即a尽量小)

a = (500-(500-x))/(500-2*x)=1 / ( 500/x - 2 )   (化简表达式得到:若使a尽量小,则x也尽量小,并且使a为非负整数)

得到:x=500/3,a=1,运输过程中耗油总量为500

因此倒数第二个加油站距离倒数第一个加油站500/3km,储油量为1000L(并在迁移到最后一个加油站过程中耗500,往最后一个加油站存500)

倒数第三个加油站同理,将之前公式里面表示存油量的500都换成1000,得到:

a = (1000-(500-x))/(500-2*x) = (500+x) / (500-2*x) = 1 + 3 / ( 500/x -2)   (要求同上)

x=100(即500/5),a=2

以此类推。。。

然后就得到了规律:x(500/3, 500/5, 500/7, 500/9...),a(1,2,3,4...)

然后就是一个数学的比较问题与最开始说过的取整之类的直白问题了,这里就略了,代码上采用直接利用规律的方法。


#include <iostream>
#include<stdio.h>
using namespace std;

const int m_max = 420;
double m[m_max] = {500};

int main()
{
    int i;
    for (i=1; i<m_max; i++) {
        m[i] = m[i-1] + 500.0/(2*i+1);
    }

    int k,n;
    scanf("%d",&k);
    while (k--) {
        scanf("%d",&n);
        for (i=1; i<m_max; i++) {
            if (m[i] >= n) {
                printf("%.3f\n",500*i+(2*i+1)*(n-m[i-1]));
                break;
            }
        }
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值