《编程之美》蚂蚁爬杆问题的扩展【1】

有一根长为L的平行于x轴的细木杆,其左端点的x坐标为0(故右端点的x坐标为L)。刚开始时,上面有N只蚂蚁,第i(1iN)只蚂蚁的横坐标为xi(假设xi已经按照递增顺序排列),方向为di(0表示向左,1表示向右),每个蚂蚁都以速度v向前走,当任意两只蚂蚁碰头时,它们会同时调头朝相反方向走,速度不变。编写程序求所有蚂蚁都离开木杆需要多长时间。

该问题是经典问题了,有O(N)的解法。昨天和赵牛同学讨论了该问题的一些扩展,赵牛均给出了精妙解答,现列出如下:

  1. i只蚂蚁什么时候走出木杆?
  2. 所有蚂蚁从一开始到全部离开木杆共碰撞了多少次?
  3. k次碰撞发生在哪个时刻?哪个位置?哪两个蚂蚁之间?
  4. 哪只蚂蚁的碰撞次数最多?
  5. 如果不是一根木杆而是一个铁圈,经过一段时间后所有蚂蚁都会回到的状态吗?这个时间的上界是多少?

扩展1的解答

现在来解决扩展1。这个解答甚是精妙,通俗点来说,我们假设每只蚂蚁都背着一袋粮食,任意两只蚂蚁碰头时交换各自的粮食然后调头。这种情况下,每次有一只蚂蚁离开木杆都意味着一袋粮食离开木杆(虽然可能已经不是它刚开始时背的那一袋了)。于是,我们可以求出每袋粮食离开木杆的时间(因为粮食是不会调头的)。又由于每袋粮食离开木杆的时间都对应某只蚂蚁离开木杆的时间,这是一种一一映射关系。现在我们要找到对应于第i只蚂蚁的那个映射。在此之前需要证明一个命题:

若一开始时有M只蚂蚁向左走,N-M只蚂蚁向右走,则最终会有M只蚂蚁从木杆左边落下,N-M只蚂蚁从木杆右边落下。

这个命题很容易证明:每次碰撞均不改变向左和向右的蚂蚁数量。于是,由于每次碰撞蚂蚁都会调头而不是穿过,最后必定是前M只蚂蚁从左边落下,后N-M只蚂蚁从木杆右边落下。由于我们知道每袋粮食是从哪边落下的,故左边落下的M袋粮食的离开木杆的时间就对应于前M只蚂蚁离开木杆的时间,右边的类似。因此,我们只需判断i和M的关系,便知道第i只蚂蚁是从左边还是右边落下。不妨假设是从左边落下,因此该蚂蚁落下的时间就等于从左边落下的第i袋粮食的落下时间。时间复杂度O(n),一遍扫描搞定。

以上内容转自:http://lam8da.sinaapp.com/?p=11O(N)

 

但以上过程描述还是过于抽象,下面我根据自己的理解整理一下:

首先,以上提出的命题是很容易看出来的,不需要再次证明。

其次,所有的蚂蚁碰面之后都调头,因此蚂蚁之间的相对位置是不会改变的。

那么,从左边落下的,必然就是左边的M个蚂蚁;从右边落下的,就是右边的N-M个蚂蚁。

有了以上这样的认识,再来看这个题目。就会发现,第i只蚂蚁,如果i<=M,则该蚂蚁肯定会从左边落下;如果i>M就会从右边落下。

假设i<=M,则该蚂蚁从左边落下;而且是向左行走的第i袋粮食。

于是,我们可以扫描所有的蚂蚁,找出所有向左行走的第i只蚂蚁,它背的就是第i袋粮食。

那么,第i袋粮食从左边落下的时间就 等于 找到的这只蚂蚁离左边起点的距离 除以  它的速度。

很清晰了吧~

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

posted @ 2012-10-20 22:03  wangicter的博客  阅读(251)  评论(0编辑  收藏  举报