火车运煤问题

来源:互联网 发布:linux vi不保存 编辑:程序博客网 时间:2024/06/02 18:55

昨天在网上看到一个有意思的数学题目,想了一会儿,没想到用数学方法来解决它,最后试了下程序来计算。

题目如下:

两地A,B相距1000公里,一列火车运能是1000吨煤,没前进一公里需要消耗1吨煤。现在有3000吨煤需要从A运到B,如何运才能使最后到达B地的煤最多?

初看似乎无解,1公里消耗1吨煤,1000吨煤达到B地就没了。在看这道题的时候,下面有一个简单的解决方法。

先运1000吨到250公里处,返回,在运1000到250公里处,三次以后,到达250公里处的煤是1750吨。然后在前进250公里,此时应该剩下1000吨煤在500公里处。然后一次运送到终点,剩下500吨达到B。由此得出500吨为最多到达B地的煤。后面有人认为这个数字不一定是最大,细想了下,确实如此,为什么一定是250公里作为关键点,而不是300公里,或者100公里。500公里是不可能,因为一个来回就为0了。所以关键就是找到250或是其他一个数字,然后算出此种运发最后的结果,然后比较才能知道是否能有比500更大的解决方案。

可以抽象为一个数学模型就是:

(1)火车拉1000吨到某一个点,在返回拉剩下的煤到之前的点,一直到拉完全部的煤到该点。

(2)到新的点之后,那么剩下的距离和剩下的煤又可以递归使用(1)中的方法。

(3) 到所剩的煤不足1000吨(也就是火车一次能全不运走)的时候就一次运完,那么减掉路上的消耗就是最后剩下的到B点的煤。

用递归方法可以实现此数学模型,而且将题目里面的数字变化之后仍然适用。相当于就是遍历的去尝试所有可能的值,然后从中找到最大值,只是将此过程将给电脑来做。

start 和 end为每次尝试的公里数的范围,比如1-499公里。

int retryCount(int totalCount, int totalLength, int start, int end)
{
        int i;
        int max = 0;

        if(totalCount <= 0 || totalLength <=0) return 0;
        if(totalCount <= totalLength) return 0;
        if(totalCount <= 1000) return totalCount - totalLength;

        for(i = start; i <= end; i++)
        {
                int loop;

         //计算达到下一个点需要的来回,一次来计算需要消耗的煤

                if(totalCount % 1000 == 0) loop = 2 * (totalCount / 1000) - 1;
                else loop = 2 * (totalCount / 1000) + 1;
                int ret = retryCount(totalCount - loop * i, totalLength - i, start, end);

                if(ret > max) max = ret;
        }

        return max;
}

但是此方法是建立在之前的那种运送方法的前提下,而且此种方法只能由计算机来算,人工完全不可行。一旦此方法不是最佳,那么由此产生的算法也是错误的。不过暂时只想到此种方法,有新的方法再来尝试,至少是可以以数学的方法计算出来的最大值。

原创粉丝点击