posts - 21,  comments - 10,  trackbacks - 0
之前看有的朋友谈百度的一道面试试题-蚂蚁问题(有一根27厘米的细木杆,在第3厘米、7厘米、11厘米、17厘米、23厘米这五个位置上各有一只蚂蚁。木杆很细,不能同时通过一只蚂蚁。开始时,蚂蚁的头朝左还是朝右是任意的,它们只会朝前走或调头,但不会后退。当任意两只蚂蚁碰头时,两只蚂蚁会同时调头朝反方向走。假设蚂蚁们每秒钟可以走一厘米的距离。编写程序,求所有蚂蚁都离开木杆的最小时间和最大时间)。关于这道题目,网上给出了很多的解释,但从整体来看,基本都是用到了等价置换(等量代换)的思想。要求最小时间,即为“最不容易”先到达两端的蚂蚁以最短的时间到达,所以我们只需找到所有蚂蚁中间的一只(共奇数只蚂蚁)或两只(共偶数只蚂蚁)到达一端的最短时间。比较麻烦的是求最长时间,有人会觉得当有很多只蚂蚁时,中间的蚂蚁们相互碰撞的次数多些会增加时间,感觉上比较复杂,可如果我们用等量代换的思想来解释就比较容易。假设中间的任意两只相邻蚂蚁即将发生碰撞,如:A ->        <-B,当A,B发生碰撞后,便有<-A    B->。A,B反向相当于<-B   A -> ,即二者继续向着原来的方向前进,对于任意相邻的发生碰撞的蚂蚁都适用,所以只需求最两端的两只蚂蚁距离两端的最远距离。由以上分析可知,如果出这样的问题,我们可以不用通过程序便能说出结果:5个点,中间蚂蚁的位置为11,即0-11-27,显然最小为11,最两端蚂蚁,0-3-27,最大为24,0-23-27,最大为23,所以最大为24。对于这个题,给出如下Java代码(随便写了几句,不符合面向对象思想)。
public class Ant {
    
public static void main(String[] args){
        
int length=27,points=5,min=0,max=0,temp_min=0,temp_max=0;
        
int[] pos={3,7,11,17,23};
        
for(int i: pos){
            temp_min
=i>length-i?length-i:i;
            temp_max
=i<length-i?length-i:i;
            
if(temp_min>min)
                min
=temp_min;
            
if(temp_max>max)
                max
=temp_max;
        }

        System.out.println(
"最短时间:"+min+"  最长时间:"+max);
    }

}
有了如上的想法,我们能做出判断,为什么还要写代码呢?其实这个问题出自Waterloo Local Contest Sep.19,2004 准确描述如下:
An army of ants walk on a horizontal pole of length l cm, each with a constant speed of 1 cm/s. When a walking ant reaches an end of the pole, it immediatelly falls off it. When two ants meet they turn back and start walking in opposite directions. We know the original positions of ants on the pole, unfortunately, we do not know the directions in which the ants are walking. Your task is to compute the earliest and the latest possible times needed for all ants to fall off the pole. 
The first line of input contains one integer giving the number of cases that follow. The data 
for each case start with two integer numbers: the length of the pole (in cm) and n, the number of ants residing on the pole. These two numbers are followed by n integers giving the position of each ant on the pole as the distance measured from the left end of the pole, in no particular order. All input integers are not bigger than 1000000 and they are separated by whitespace. 

For each 
case of input, output two numbers separated by a single space. The first number is the earliest possible time when all ants fall off the pole (if the directions of their walks are chosen appropriately) and the second number is the latest possible such time. 

Sample Input
2
10 3
2 6 7
214 7
11 12 7 13 176 23 191

Sample Output
4 8
38 207

在这里给出相应的c++代码:
#include<iostream>
using namespace std;
int main()
{
    
int cases,l,n,min,max,temp_min,temp_max,pos;
    cin
>>cases;
    
while(cases--)
    
{
        cin
>>l>>n;
        min
=0;
        max
=0;
        
while(n--)
        
{
            cin
>>pos;
            temp_min
=pos>l-pos?l-pos:pos;
            temp_max
=pos<l-pos?l-pos:pos;
            
if(temp_min>min)
                min
=temp_min;
            
if(temp_max>max)
                max
=temp_max;
        }

        cout
<<min<<' '<<max<<endl;
    }

    
return 0;
}
posted on 2008-05-10 11:28 dreamingnest 阅读(936) 评论(7)  编辑  收藏 所属分类: 应用程序

FeedBack:
# re: 关于蚂蚁问题(Ants)
2008-05-10 13:29 | 漠漠
确实是这样,我们可以想象成它们碰撞后并没有反向而是继续直着向前走:)  回复  更多评论
  
# re: 关于蚂蚁问题(Ants)
2008-05-10 14:14 | 银河使者
楼主这个想法非常的好,打满分。
下面用数学归纳法证明一下这个算法。让我们先来看最简单的形式(m=1),有两只蚂蚁的情况,假设细木杆的长度为n,两只蚂蚁的位置分别为p1和p2。并且p2 > p1。其他的条件如原题。下面分别用p1和p2来代表两只蚂蚁。

对于两只蚂蚁,方向组合只有四种,分别如下:
1. p1、p2都向左 最长时间:time(p2)
2. p1、p2都向右 最长时间:time(p1)
3. p1向左、p2向右 最长时间:max(time(p1), time(n - p2))
4. p1向右、p2向左(这种情况会发生碰撞)

最长时间:max(time(n - p1), time(p2))

对于这种情况,实际上p2的时间为time(((p2 - p1) / 2 ) * 2 + n - p2 )= time(n - p1)
p1的时间为time(((p2 - p1) / 2 ) * 2 + p1) = time(p2),
从最终结果看,A- >, < -B 就相当于< -B , A - > 相当于A、B互相穿越而过,并且B只走到A最初的位置,而A也只走到B最初的位置。

从上面四种情况的最长时间可看出,正好将两种蚂蚁p1和p2可能存在的的四种可能:p1、p2、n - p1、n-p2 。我们要做的就是求这四个值的最大值,即max(time(p1)、time(p2)、time(n - p1)、time(n-p2))。 如果用文字来描述的话,就是任意一只蚂蚁到达两端的最长时间就是最终结果。

最简单的情况已经ok了,现在假设m只蚂蚁也成立,那么这m只蚂蚁也可以看成是一只蚂蚁,而m+1只蚂蚁当然就相当于两只蚂蚁了。所以
m = 1 成立
假设m成立
而证明了m+1也成立
所以“任意一只蚂蚁到达两端的最长时间就是最终结果”的结论成立  回复  更多评论
  
# re: 关于蚂蚁问题(Ants)
2008-05-12 14:22 | blues
其实楼主的思想比较好,本人觉得这种题目根本不需要用程序来计算,
我认为还有更好的方法,我在原文给出了最长时间的分析。
这里我加上最短时间分析:

其实文中蚂蚁相撞两蚂蚁调头
可以这样看问题,如果相撞后,杆可以过两只蚂蚁
蚂蚁不调头,即擦肩而过,继续沿原来方向前进(与调头是一样的,只是换了一只蚂蚁而已)
这样问题就简化了,呵呵。
即所有蚂蚁中离杆其中一端最远的那只蚂蚁,即为最长时间。
即27-3=24

同理,最短时间为
所有蚂蚁使用时间:A最短是3, B最短是7, C最短11, D最短是10, E最短是4。
所以总的最短时间为11.

不知道小弟的思路是否正确?~~~~
  回复  更多评论
  
# re: 关于蚂蚁问题(Ants)
2008-05-12 15:26 | dreamingnest
你为什么确定27-3=24是便是最长的呢?我觉得你说的“即所有蚂蚁中离杆其中一端最远的那只蚂蚁,即为最长时间”和“所有蚂蚁使用时间:A最短是3, B最短是7, C最短11, D最短是10, E最短是4”中的两个“所有”和我解释的还不太一样,呵呵。

·最长时间:是按照你说的“蚂蚁不调头,即擦肩而过,继续沿原来方向前进(与调头是一样的,只是换了一只蚂蚁而已)”这样,但有两点说明:(1)通过分析,我们只需判断最两端的两只蚂蚁便足够了,证明见二楼“银河使者”的解释。(2)一定要求出4个数进行比较后才可以,假设最左端和最右端的位置为L和R,中长度为T,那么最长的时间为max(max(L,T-L),max(R,T-R))。

·最短时间:通过分析后,也只需看最中间的一个(共奇数蚂蚁)或两个(共偶数蚂蚁)蚂蚁到达某一端的最短时间,对于奇数:min(L,T-L),对于偶数:max(min(L,T-L),min(R,T-R))。

·通过程序来实现是有必要的,这算是一道模拟题目,可在情况类似的计算应用中会遇到,正如英文描述中可能出现1000000数量级别的,这样我们便无法直接得出结果。此题能作为面试题,而不是笔试题,就是在考察一种思想,避开“一根不能同时通过两只蚂蚁”的迷惑。

·感谢大家能仔细讨论这个问题,写程序相信每个人都能实现,只是这道题给我们的启发是非常大的~  回复  更多评论
  
# re: 关于蚂蚁问题(Ants)
2008-05-12 15:53 | blues
二楼的数学式和证明我觉得有点晕,没细看。 原理应该也一样
至于为什么说27-3是最长,我中间跳跃一些而已。
就是观察分析了两端的蚂蚁后说的, A离左边3, E离右边4。
所以最长就是27-3=24。 上一句分析我省略了而已,SORRY。

最短:
我只是将五个蚂蚁的最短时间列出来而已, 最长时间列出来没意义了。
如果用式子总结便是: 最靠近杆中间点的那个蚂蚁的最短时间,即C距离左边。


@dreamingnest
  回复  更多评论
  
# re: 关于蚂蚁问题(Ants)
2008-06-12 16:00 | zdh
这个问题看到实质就很简单,所有的蚂蚁都是相同的蚂蚁,因此可以看成所有的蚂蚁都可以穿过对面爬过来的蚂蚁就ok啦,最长时间就是两端的蚂蚁向另一端爬出去,最短的就是两端的四个蚂蚁向所在端爬出:)  回复  更多评论
  
# re: 关于蚂蚁问题(Ants)
2008-06-12 16:06 | zdh
实际过程可以这么进行抽象模拟:
序列中的元素带有方向,进行负值部分移动到负值区域,正值部分移动到正值区域时就不再发生碰撞,此时绝对值最小的值决定剩余爬行时间  回复  更多评论
  

标题  
姓名  
主页
验证码 *  
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-05-10 12:05 编辑过
 




<2008年5月>
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

常用链接

留言簿

随笔分类(15)

随笔档案(22)

外面的世界

这里的朋友

搜索

  •  

最新评论

阅读排行榜

评论排行榜