一道公司笔试题目,求算法?

时间:2022-03-30 14:41:08
假设你是一个懂得编程的山西煤老板。
你在煤矿区采了3000吨煤,准备运往
1000公里以外的市场销售。在运输途中
只能够采用火车这一种运输途径。而且
只有一辆火车,火车一次最多运载1000吨煤。
这辆火车只能够以烧煤作为前进的动力,
并且每前进1公里将消耗掉1吨煤。
请问煤老板最终能够有多少吨煤运到市场销售,
请给出计算过程,以及答案。
ps:在火车的运输途中,火车可以在任意的
地方卸货,掉头,并且卸货,掉头不计成本。

12 个解决方案

#1


绿盟?

#2


又来一个 酷壳 上的题目。这个题目很流行啊。

#4


乍看无解,其实题目暗含个条件:煤可以在半路卸下来。

换个思维来思考该题目:在条件不变的情况下,如果运输距离不受限制在矿区到市场之间,那么火车的最大运输距离是多少?假定为S,由于火车跑一公里需要一吨煤,所以(S-1000)就是题目的答案。

那么火车的运输距离如何才能最大呢,当然是火车运输单位公里时平均燃烧的煤越少,火车的运输距离越大,也就是说火车运输距离与燃烧煤吨数之间的比值越大,火车的运输距离越大。

从最简单的情况开始分析,矿区只有1000吨煤时,运输距离与燃烧煤吨数的比值为:1000/1000 = 1,火车的最大运输距离是1000公里。

矿区有2000吨煤时,由于火车最多只能装1000吨煤,所以有1000吨煤需要火车往返1次运输,假设往返运输的距离为S1,火车往返运输时,运输距离与燃烧煤吨数的比值为:S1 / 3S1 = 1/3

这样有1000吨煤需要往返1次运输,运输距离与燃烧煤吨数的比值为1/3,1000吨煤直接运输,火车最大运输距离为:1000 + 1000 * 1 / 3公里.

矿区有3000吨煤时,有1000吨煤需要往返2次运输,运输距离与燃烧煤吨数的比值为1/5,1000吨煤需要往返1次运输,运输距离与燃烧煤吨数的比值为1/3,1000吨煤直接运输,火车最大运输距离为:1000 + 1000 * 1 /3 + 1000 * 1 /5 = 1533.333…

所以面试题的答案为1533.333… – 1000 = 533.333…吨。

如果继续递推下去,可以发现每增加1000吨煤,运输新增加的煤时,运输距离与燃烧煤吨数的比值会有规律的减小,如下:

1 1/3 1/5 1/7 1/9 1/11 …… 1/(2n+1)

#5


其实这个问题有很多地方需要论证,这才是关键。如果这些都是对的成立的,那么解决方法对于大家都不是很难。我看了几处相关的文章,都没有很好的论证。

比如我列几个问题的论证(有的有过论证,但不充分。有些我知道论证方法,列出来是为了供大家参考)
1、为什么最后一个存油站,要离目标500KM,存500升油,而不是离目标300KM存300升油?或者离目标200KM存200升油?或者在500KM处放100升,在600KM处400升?
2、建多少个存油点合适?规律是什么?比如,到达501米处应该建几个存油点,为什么?分别应该建在什么位置上合理?
3、存油点之间是什么关系最为合适?比如有1、2、3、4四个点的话(如果2可直接运到4,或可达4的话),4的油是从3运过去还是同时也接受2的油?为什么?如果只是从3运,那论证其合理性和优势。
4、如果每次都满载油的话,那必定有剩余,即使1000没有剩,题目改为999就会有剩,或者501等。也就是说算法必定考虑剩油的问题,那么这个数字放到开始还是最后来处理,为什么?

如果下面假设都成立,我想一般人都会解:
1、最后在500KM存500L油且车能够刚好到达500KM处,是最好的结束环节;
2、每一个存油点都只是从前一个存油点收油,送往下一个存油点,不涉及第三存油点间的关联;
3、送油与车到终点是不同的,假定除最后一次离开起点或某存油点的油可以不满,其它时间装油都得装满;
4、两点间送油,以两趟为最省,即去回去,三次路过之间的距离。(这是看有些人按这个算的,但实际不一定成立)
还有很多问题需要论证,不列了。

#6


我好象搞错了。这不是过车的问题,是运煤的问题,而且有定数的。那就两说了。相对简单很多。

火车就不考虑回来的问题了哈!

先来论证的一个运输效率的问题:
假设每次装1000吨煤准备送到距离X处,(X小于500,因为过了这个就回不来了)
那么显然是分3车。
前两次到距离X处,烧去4X吨,第三次烧X吨,
即到达X时耗煤5X
如果剩余煤小于等于2000,则需要耗煤3X
如果剩余煤小于等于1000,则需要耗煤X
显然,越往后,耗煤越少,但多运些煤是目的,所以总是会期望把所有的煤都装上车的。

考虑一下:如果煤大于2000时,运到一个点,还大于2000,那就是还要按5X耗煤计,那么,有必要分多次么?这样车不满载,应该会浪费(就即使不浪费,与一次降到2000也没有差别,因为这期间每走XKM就烧5X吨煤)。所以要让第一次运完,刚好变成2000的剩余,然后再刚好变成1000的剩余,在一次运到。当然没变成1000就到了,那是最好。
这样的话,
3000-5X=2000
X=200KM,
2000-3X=1000
X=1000/3KM
剩下的运到终点
结果为:
1000吨-(1000KM-200KM-1000/3KM)*(1吨/KM)
=1000-1000+200+1000/3
约为533.33吨可以卖。

#7


wcyoot
说的,呵呵

问题变形:

 

一个商人骑一头驴要穿越1000公里长的沙漠,去卖3000根胡萝卜。已知驴一次性可驮1000根胡萝卜,但每走1公里又要吃掉1根胡萝卜。问:商人最多可卖出多少胡萝卜?

同样的道理:为使利益最大,需要建立临时补给站。且临时补给站的存货应该是驴最大负重的整数倍。此题与第一题的不同之处在于在最小消耗下运送最大的量。

设沙漠两端AB,最后的补给站为C1,则C1 = 1000,距离B点还有x公里,d1 = x>=0.目标x最小。

C2点:

C2 = 1000*2,

d2 = d1+x2 = d1+1000/3 = x+1000/3;

 

C3点:

C3 = 1000*3

d3 = d2+x3 = x + (1/3+1/5)*1000

 

di = x+(1/3+1/5+...+1/(2*i-1))*1000

Ci = 1000*i

 

商人要卖出最多的胡萝卜就要使Cn = 初始总量W。即把起点也看作一个临时补给站。起点就是C3

商人做多可卖出的胡萝卜y = 1000-x = (1/3+1/5)*1000 = 533

#8


火车往前开的时候车上的油要尽量多,即每次装油完毕时,除非该地没有更多的油了,否则火车应该装满,这样运输单位量的油的成本最低。

火车往回开的时候车上的油要尽量少,即每次往回开并且到达存油点的时候,车上剩余的油不应该影响火车装剩余的油,本例中刚好可整除,所以火车回到原点的时候应该没有剩油最优。

火车把油存放在一个可以存到容量整数倍的点,是由于如果在该阶段把油再往前运,而该阶段火车的来回次数必然比下一阶段火车来回的次数多,如果再往前运不足以减少下一阶段火车来回的次数,那么该阶段一定会额外浪费油量。也就是尽量让来回次数少的运输阶段距离更长。

#9


我用Php写了代码计算了一下,最后结果是499,哪里错了么?

<?php
$r=array();
$nowmax=0;
$rnum=0;
for($x=1;$x<500;$x++)
{
  $xstore=1000-$x*2;
  for($y=1;$y<1000-$x;$y++)
  {
    if(($y>=$x)&&($y<=500+$x*0.5)&&($y<=500+$xstore*0.5))
    {
      ////$ystore=1000+$xstore-$y*2;
        for($ygetx=0;$ygetx<$xstore+1;$ygetx++)
        {
          if($ygetx<$x)
          {
            $xstore02=$xstore-$ygetx;
            $ystore=1000+$ygetx-$y*2;
                
                //Calculation of final results
                $endx=$x>$xstore02?$xstore02:$x;
                $endy=($y-$endx)>$ystore?$ystore:($y-$endx);
                $endstore=$endx+$endy;
                $rnum++;
                if($endstore>$nowmax)
                {
                   $nowmax=$endstore;
                   ////$r[]=$endstore;
                   $r['x']=$x;
                   $r['y']=$y;
                   $r['xstore']=$xstore;
                   $r['xstore02']=$xstore02;
                   $r['ygetx']=$ygetx;
                   $r['ystore']=$ystore;
                   $r['endx']=$endx;
                   $r['endy']=$endy;
                   $r['endstore']=$endstore;
                   $r['rnum']=$rnum;
                  }
          }
        }
        
    }
  }
}
echo $rnum;
echo'<br>';
print_r($r);
?>


最后输出如下

27847083 产生的 合理结果的个数
Array (
[x] => 249 第 1趟火车卸货并返回的地点
[y] => 499 第 2趟火车卸货并返回的地点
[xstore] => 502 第 1趟火车中途卸货点最初的存货量
[xstore02] => 254 第 1趟火车中途卸货点被第 2趟火车取走部分煤后的剩余存货量
[ygetx] => 248 第 2趟火车从第一趟火车卸货点取走的煤
[ystore] => 250 第 2趟火车中途卸货点最初的存货量
[endx] => 249 第 3趟火车取走第 1趟火车存货点煤的数量
[endy] => 250 第 3趟火车取走第 2趟火车存货点煤的数量
[endstore] => 499  最后能达到终点的煤的数量
[rnum] => 12966125 此结果是第几条 合理的结果

#10


上面我发现错误在哪里了
if($ygetx<$x)
应该改成
if($ygetx<=$x)

但最后得出结果如下
27986027
Array ( [x] => 250 [y] => 500 [xstore] => 500 [xstore02] => 250 [ygetx] => 250 [ystore] => 250 [endx] => 250 [endy] => 250 [endstore] => 500 [rnum] => 13169375 ) 

还是到不了前面说的533啊
前面是不是不考虑 火车返回要消耗煤

#11


这个题目,应该不需要写程序的,因为也不需要叠代,几次就搞定了。

#12


一道公司笔试题目,求算法?

#1


绿盟?

#2


又来一个 酷壳 上的题目。这个题目很流行啊。

#3


#4


乍看无解,其实题目暗含个条件:煤可以在半路卸下来。

换个思维来思考该题目:在条件不变的情况下,如果运输距离不受限制在矿区到市场之间,那么火车的最大运输距离是多少?假定为S,由于火车跑一公里需要一吨煤,所以(S-1000)就是题目的答案。

那么火车的运输距离如何才能最大呢,当然是火车运输单位公里时平均燃烧的煤越少,火车的运输距离越大,也就是说火车运输距离与燃烧煤吨数之间的比值越大,火车的运输距离越大。

从最简单的情况开始分析,矿区只有1000吨煤时,运输距离与燃烧煤吨数的比值为:1000/1000 = 1,火车的最大运输距离是1000公里。

矿区有2000吨煤时,由于火车最多只能装1000吨煤,所以有1000吨煤需要火车往返1次运输,假设往返运输的距离为S1,火车往返运输时,运输距离与燃烧煤吨数的比值为:S1 / 3S1 = 1/3

这样有1000吨煤需要往返1次运输,运输距离与燃烧煤吨数的比值为1/3,1000吨煤直接运输,火车最大运输距离为:1000 + 1000 * 1 / 3公里.

矿区有3000吨煤时,有1000吨煤需要往返2次运输,运输距离与燃烧煤吨数的比值为1/5,1000吨煤需要往返1次运输,运输距离与燃烧煤吨数的比值为1/3,1000吨煤直接运输,火车最大运输距离为:1000 + 1000 * 1 /3 + 1000 * 1 /5 = 1533.333…

所以面试题的答案为1533.333… – 1000 = 533.333…吨。

如果继续递推下去,可以发现每增加1000吨煤,运输新增加的煤时,运输距离与燃烧煤吨数的比值会有规律的减小,如下:

1 1/3 1/5 1/7 1/9 1/11 …… 1/(2n+1)

#5


其实这个问题有很多地方需要论证,这才是关键。如果这些都是对的成立的,那么解决方法对于大家都不是很难。我看了几处相关的文章,都没有很好的论证。

比如我列几个问题的论证(有的有过论证,但不充分。有些我知道论证方法,列出来是为了供大家参考)
1、为什么最后一个存油站,要离目标500KM,存500升油,而不是离目标300KM存300升油?或者离目标200KM存200升油?或者在500KM处放100升,在600KM处400升?
2、建多少个存油点合适?规律是什么?比如,到达501米处应该建几个存油点,为什么?分别应该建在什么位置上合理?
3、存油点之间是什么关系最为合适?比如有1、2、3、4四个点的话(如果2可直接运到4,或可达4的话),4的油是从3运过去还是同时也接受2的油?为什么?如果只是从3运,那论证其合理性和优势。
4、如果每次都满载油的话,那必定有剩余,即使1000没有剩,题目改为999就会有剩,或者501等。也就是说算法必定考虑剩油的问题,那么这个数字放到开始还是最后来处理,为什么?

如果下面假设都成立,我想一般人都会解:
1、最后在500KM存500L油且车能够刚好到达500KM处,是最好的结束环节;
2、每一个存油点都只是从前一个存油点收油,送往下一个存油点,不涉及第三存油点间的关联;
3、送油与车到终点是不同的,假定除最后一次离开起点或某存油点的油可以不满,其它时间装油都得装满;
4、两点间送油,以两趟为最省,即去回去,三次路过之间的距离。(这是看有些人按这个算的,但实际不一定成立)
还有很多问题需要论证,不列了。

#6


我好象搞错了。这不是过车的问题,是运煤的问题,而且有定数的。那就两说了。相对简单很多。

火车就不考虑回来的问题了哈!

先来论证的一个运输效率的问题:
假设每次装1000吨煤准备送到距离X处,(X小于500,因为过了这个就回不来了)
那么显然是分3车。
前两次到距离X处,烧去4X吨,第三次烧X吨,
即到达X时耗煤5X
如果剩余煤小于等于2000,则需要耗煤3X
如果剩余煤小于等于1000,则需要耗煤X
显然,越往后,耗煤越少,但多运些煤是目的,所以总是会期望把所有的煤都装上车的。

考虑一下:如果煤大于2000时,运到一个点,还大于2000,那就是还要按5X耗煤计,那么,有必要分多次么?这样车不满载,应该会浪费(就即使不浪费,与一次降到2000也没有差别,因为这期间每走XKM就烧5X吨煤)。所以要让第一次运完,刚好变成2000的剩余,然后再刚好变成1000的剩余,在一次运到。当然没变成1000就到了,那是最好。
这样的话,
3000-5X=2000
X=200KM,
2000-3X=1000
X=1000/3KM
剩下的运到终点
结果为:
1000吨-(1000KM-200KM-1000/3KM)*(1吨/KM)
=1000-1000+200+1000/3
约为533.33吨可以卖。

#7


wcyoot
说的,呵呵

问题变形:

 

一个商人骑一头驴要穿越1000公里长的沙漠,去卖3000根胡萝卜。已知驴一次性可驮1000根胡萝卜,但每走1公里又要吃掉1根胡萝卜。问:商人最多可卖出多少胡萝卜?

同样的道理:为使利益最大,需要建立临时补给站。且临时补给站的存货应该是驴最大负重的整数倍。此题与第一题的不同之处在于在最小消耗下运送最大的量。

设沙漠两端AB,最后的补给站为C1,则C1 = 1000,距离B点还有x公里,d1 = x>=0.目标x最小。

C2点:

C2 = 1000*2,

d2 = d1+x2 = d1+1000/3 = x+1000/3;

 

C3点:

C3 = 1000*3

d3 = d2+x3 = x + (1/3+1/5)*1000

 

di = x+(1/3+1/5+...+1/(2*i-1))*1000

Ci = 1000*i

 

商人要卖出最多的胡萝卜就要使Cn = 初始总量W。即把起点也看作一个临时补给站。起点就是C3

商人做多可卖出的胡萝卜y = 1000-x = (1/3+1/5)*1000 = 533

#8


火车往前开的时候车上的油要尽量多,即每次装油完毕时,除非该地没有更多的油了,否则火车应该装满,这样运输单位量的油的成本最低。

火车往回开的时候车上的油要尽量少,即每次往回开并且到达存油点的时候,车上剩余的油不应该影响火车装剩余的油,本例中刚好可整除,所以火车回到原点的时候应该没有剩油最优。

火车把油存放在一个可以存到容量整数倍的点,是由于如果在该阶段把油再往前运,而该阶段火车的来回次数必然比下一阶段火车来回的次数多,如果再往前运不足以减少下一阶段火车来回的次数,那么该阶段一定会额外浪费油量。也就是尽量让来回次数少的运输阶段距离更长。

#9


我用Php写了代码计算了一下,最后结果是499,哪里错了么?

<?php
$r=array();
$nowmax=0;
$rnum=0;
for($x=1;$x<500;$x++)
{
  $xstore=1000-$x*2;
  for($y=1;$y<1000-$x;$y++)
  {
    if(($y>=$x)&&($y<=500+$x*0.5)&&($y<=500+$xstore*0.5))
    {
      ////$ystore=1000+$xstore-$y*2;
        for($ygetx=0;$ygetx<$xstore+1;$ygetx++)
        {
          if($ygetx<$x)
          {
            $xstore02=$xstore-$ygetx;
            $ystore=1000+$ygetx-$y*2;
                
                //Calculation of final results
                $endx=$x>$xstore02?$xstore02:$x;
                $endy=($y-$endx)>$ystore?$ystore:($y-$endx);
                $endstore=$endx+$endy;
                $rnum++;
                if($endstore>$nowmax)
                {
                   $nowmax=$endstore;
                   ////$r[]=$endstore;
                   $r['x']=$x;
                   $r['y']=$y;
                   $r['xstore']=$xstore;
                   $r['xstore02']=$xstore02;
                   $r['ygetx']=$ygetx;
                   $r['ystore']=$ystore;
                   $r['endx']=$endx;
                   $r['endy']=$endy;
                   $r['endstore']=$endstore;
                   $r['rnum']=$rnum;
                  }
          }
        }
        
    }
  }
}
echo $rnum;
echo'<br>';
print_r($r);
?>


最后输出如下

27847083 产生的 合理结果的个数
Array (
[x] => 249 第 1趟火车卸货并返回的地点
[y] => 499 第 2趟火车卸货并返回的地点
[xstore] => 502 第 1趟火车中途卸货点最初的存货量
[xstore02] => 254 第 1趟火车中途卸货点被第 2趟火车取走部分煤后的剩余存货量
[ygetx] => 248 第 2趟火车从第一趟火车卸货点取走的煤
[ystore] => 250 第 2趟火车中途卸货点最初的存货量
[endx] => 249 第 3趟火车取走第 1趟火车存货点煤的数量
[endy] => 250 第 3趟火车取走第 2趟火车存货点煤的数量
[endstore] => 499  最后能达到终点的煤的数量
[rnum] => 12966125 此结果是第几条 合理的结果

#10


上面我发现错误在哪里了
if($ygetx<$x)
应该改成
if($ygetx<=$x)

但最后得出结果如下
27986027
Array ( [x] => 250 [y] => 500 [xstore] => 500 [xstore02] => 250 [ygetx] => 250 [ystore] => 250 [endx] => 250 [endy] => 250 [endstore] => 500 [rnum] => 13169375 ) 

还是到不了前面说的533啊
前面是不是不考虑 火车返回要消耗煤

#11


这个题目,应该不需要写程序的,因为也不需要叠代,几次就搞定了。

#12


一道公司笔试题目,求算法?