《编程之美》蚂蚁爬杆问题的扩展【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袋粮食从左边落下的时间就 等于 找到的这只蚂蚁离左边起点的距离 除以  它的速度。

    很清晰了吧~

     

    评论 1
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值