`

(转)《编程之美》蚂蚁爬杆问题的扩展

 
阅读更多

转自http://lam8da.sinaapp.com/?p=11

 

《编程之美》4.7节描述了蚂蚁爬杆问题,把所有具体数字都表示成字母后变为形如如下形式的问题:

有一根长为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只蚂蚁向左走,NM只蚂蚁向右走,则最终会有M只蚂蚁从木杆左边落下,NM只蚂蚁从木杆右边落下。

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

扩展2的解答

对于扩展2,我们只需求得每个蚂蚁的碰撞次数,然后累加即可。在这里我们换一种思路,把碰撞调头看成不调头而继续向前(穿过),则容易看出原问题 (碰撞次数)就变为求穿过的次数(因为速度大小不变,原来的每次碰撞都对应于现在的一次穿过)。则对于每只向左的蚂蚁,它只会“穿过”那些在它左边的向右 走的蚂蚁。因此,每只蚂蚁“穿过”的蚂蚁次数等于刚开始时在它前进方向上与它前进方向相反的蚂蚁个数。时间复杂度也是O(N)。改为用粮食的观点来理解也是可以的。

扩展3的解答

第3个扩展问题有点复杂。首先我们假设v为0.5个单位长度每秒,每个蚂蚁刚开始时都处于整点处,这样每次碰撞都发生在整秒处。这个假设有个好处,就是我们可以二分第k次 碰撞的时刻。如果碰撞时刻是浮点数,这个二分有可能永远不会终止。我们还是看成每个蚂蚁驮着一袋粮食,那么每袋粮食易主(即从一个蚂蚁身上交换到另一个蚂 蚁身上)时,就发生了一次碰撞。由于粮食的方向是固定不变的,我们可以很容易求出每一袋粮食在它的“前进”方向上的所有易主时刻(它易主的次数等于扩展2 中的“穿过”次数)。这样,我们的问题就等价于:

找到最小的时间t,使得易主时刻小于或等于t的易主次数大于或等于k

由于现在所有碰撞(易主)的时刻都是整点,故我们可以二分t,然后用线性复杂度找出易主时刻小于或等于t的易主次数。整个复杂度为O(Nlog(|maxtmint|),其中maxt和mint分别表示第一次和最后一次碰撞的时刻,均可在O(N)时间内求出。

在上一段中,要想使用线性时间复杂度求出易主时刻小于或等于t的易主次数还需要一点技巧。可以这样:用一个数组pi表示第i个向右走的蚂蚁的初始位置,当扫描到第j个向左走的蚂蚁时,假设得到的中值点为i(即p0到第pi个位置上对应的粮食和该袋粮食的易主时刻均大于t)。由于该袋粮食向左易主的时刻是递增的,而下一个向左走的蚂蚁的初始位置又大于当前(第j个向左走的)蚂蚁,故对于下一个蚂蚁ant来说,p0到第pi个位置上对应的粮食和ant所驮粮食的易主时刻也一定大于t。即中值点的位置是单调的。因此可以在均摊O(N)的时间内算出所求个数。

求出时刻的同时我们也求出了位置,故第二小问也解决。接下来要求哪两个蚂蚁发生了这次碰撞(如果同时存在多个碰撞求出任意一个即可)。其实,我们只需要求出每袋粮食在t时刻的位置即可。因为每袋粮食必然对应于一个驮着它的蚂蚁,故我们只需对这些粮食的位置排序,找出位置相同的粮食以及其下标(即从左到右第几个),也就找出了那对蚂蚁了。

扩展4的解答

对于第4个扩展,只要求出每只蚂蚁的碰撞次数即可。这也解决了扩展2的解答中原始思路。首先由扩展1的解答我们可以知道每只蚂蚁最终是往左还是右掉下去,然后假设第i只蚂蚁最终往左掉下,而开始时刻其左边有r只向右走的蚂蚁,则它至少要朝左边碰撞r次才能把左边的蚂蚁全撞成向左的状态。倘若它一开始就是向左的,则共要碰撞2r次,否则为2r+1次。这样利用一个数组和几个计数器仍能在O(N)时间内求出每个蚂蚁的碰撞次数,取最大那个即可。

扩展5的解答

这个问题看起来挺复杂,其实很简单。假设环长为L,则一个蚂蚁走完一圈需要T=L/v的时间。首先,还是像上面的讨论那样假设每个蚂蚁都驮着一袋粮食。那么,经过T时间后所有粮食都回到了原来的位置。由于每袋粮食都对应一个蚂蚁,而蚂蚁每次碰撞都会调头,因此蚂蚁的相对位置是不变的,这就说明经过T时间后蚂蚁循环移动了。假设移动了s个位置,即每个蚂蚁都到达它往右第s个蚂蚁的初始位置,那么,类似地,再经过T时间,当前状态仍会循环移动s个位置。容易看出这是一个最小公倍数问题:循环移动多少个s次之后每个蚂蚁回到自己位置?答案为LCM(N,s)/s,于是最多经过Tmax=LCM(N,s)/sTNT时间,每个蚂蚁都至少回到原地一次。

除了以上几个扩展,还有一些个人认为比较变态的扩展,有的没空仔细想,有的暂时没想到解法,也列出如下,欢迎拍砖:

  1. 如果每只蚂蚁的速度不一样(这就有可能由于追赶而产生碰撞,此时根据动量守恒定律:(,速度互换),上述扩展问题的答案是什么呢?
  2. 如果蚂蚁在一个平面上运动,同样也是碰头后原路返回(注意这不等同于两只蚂蚁交换继续前进),问是否所有蚂蚁都能最终离开平面?
  3. 在上述情况下,如果最终能离开平面,离开平面需要多长时间?
  4. 在上述情况下,回答关于一维的前文讨论的每个问题。

另外,赵牛同学又提出了一些更bt的扩展,如下:

  1. 假设每个蚂蚁都有重量,两只蚂蚁碰撞时轻的那个有一定几率从旁边被撞下去:(,那又该怎样?
  2. 假设不是被撞下去而是有一定几率被撞晕而停滞几秒,那又该怎样?
  3. blablabla...
分享到:
评论

相关推荐

    蚂蚁爬杆问题

    蚂蚁爬杆问题 A.B.C三只蚂蚁不同速度在一个杆上爬行,求蚂蚁爬出杆的时间问题

    1蚂蚁爬杆之动态演示

    在这个场景中,“1蚂蚁爬杆之动态演示”是一个项目,它使用编程来模拟蚂蚁爬杆的行为。该项目可能包含32种不同的选择或策略,每种选择都可能导致蚂蚁爬杆的不同结果,这可能是为了展示算法的多样性和复杂性,或者是...

    蚂蚁爬杆问题(面向对象)

    在本案例中,“蚂蚁爬杆问题”是一个典型的OOP应用场景,我们可以用C#语言来实现。下面我们将详细探讨这个问题以及如何用面向对象的方式去解决它。 首先,我们需要定义一个“蚂蚁”类(Ant),这个类至少包含两个...

    蚂蚁爬杆+图形界面+C#+ide=vs08

    某企业面试编程题:蚂蚁爬杆 有一根300厘米的细木杆,在第30厘米、80厘米、110厘米、160厘米、250厘米这五个位置上各有一只蚂蚁。木杆很细,不能同时通过两只蚂蚁。开始时,蚂蚁的头朝左还是朝右是任意的,它们只会...

    c++蚂蚁爬杆问题

    蚂蚁爬杆自己写的,希望大神能够帮助我写代码的质量,有什么问题随便提出来,自己一定会改正的谢谢

    蚂蚁爬杆题目与分析.txt

    通过以上分析和实现,我们可以看到,使用对象的方法来解决“蚂蚁爬杆”这类问题是一种非常有效的方式。它不仅能够清晰地表达问题的关键要素,还能够方便地通过编程语言进行实现。此外,这种解题思路还可以扩展到更多...

    蚂蚁爬杆游戏

    "蚂蚁爬杆游戏"是一款基于C#编程语言开发的小型计算机游戏,其核心玩法是模拟蚂蚁在一根垂直的杆上爬行,目标是计算出所有蚂蚁都安全离开杆子的最短和最长时间。这个游戏涉及到计算机科学中的算法设计、数据结构和...

    蚂蚁爬行问题源码

    蚂蚁爬行问题就是一个这样的例子,它源于对真实世界蚂蚁行为的观察,然后通过编程来模拟这种行为。在这个问题中,我们使用Java语言来构建一个具有图形用户界面(GUI)的游戏,模拟5只蚂蚁在一根杆子上随机移动的情景...

    27厘米的细木杆上蚂蚁爬杆

    6. **异常处理**:在程序中,对于蚂蚁爬出木杆的情况,通过设置`hasRemove`标志来终止蚂蚁的移动,并清空当前位置的蚂蚁。 7. **时间复杂度**:由于每秒蚂蚁只能移动一厘米,且每次移动都会检查是否与其他蚂蚁碰撞...

    蚂蚁爬杆27厘米的细木杆

    有一根27厘米的细木杆,在第3厘米、7厘米、11厘米、17厘米、23厘米这五个位置上各有一只蚂蚁。 木杆很细,不能同时通过一只蚂蚁。 开始时,蚂蚁的头朝左还是朝右是任意的,它们只会朝前走或调头,但不会后退。 当...

    使用C++实现小蚂蚁爬行

    这个问题的核心是通过编程语言模拟蚂蚁在一条线上的运动行为,包括它们的相遇和方向变化。让我们深入探讨这个主题。 首先,我们需要理解问题的基本模型。假设线是一个一维空间,蚂蚁们在这个空间上移动,每个蚂蚁都...

    怎样以Java编程解决趣味蚂蚁问题.pdf

    ### 如何以Java编程解决趣味蚂蚁问题 #### 1. 问题背景与描述 趣味蚂蚁问题是一个在网络上流行的智力挑战题目。题目中提到的情况是:在一个27厘米长的细木杆上,在第3厘米、7厘米、11厘米、17厘米、23厘米这五个...

    PHP实现的蚂蚁爬杆路径算法代码

    在蚂蚁爬杆问题中,目标是找到所有蚂蚁离开杆子的最短和最长时间。 在这个PHP实现的版本中,我们首先定义了一个27厘米的杆子,上有5个位置分别有蚂蚁,蚂蚁只能朝前走或者调头,但不能后退。当两只蚂蚁相遇时,它们...

    14.神奇画笔-蚂蚁回家-项目源码与素材,Scratch少儿编程,经典教学作品,儿童益智游戏

    《神奇画笔-蚂蚁回家》是一款专为少儿设计的编程教育项目,旨在通过Scratch编程语言,引导孩子们学习编程基础知识,提升逻辑思维能力和创新意识。本项目作为一个经典的教学作品,将编程与儿童益智游戏相结合,使学习...

    爆款少儿青少年scratch编程第11课:蚂蚁寻路

    A53课程制作 爆款爆款少儿青少年scratch编程是包括教程制作完整课程,里面包括教学步骤,教学视频,教学素材,教学课件pdf,教学课件word,课程源码。课程内容大致如下所示:资源:.│ 第*课***_580.doc│ 第*课:***...

    蚂蚁感冒问题

    每只蚂蚁都只能沿着杆子向前爬,速度是1厘米/秒。 当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行。 这些蚂蚁中,有1只蚂蚁感冒了。并且在和其它蚂蚁碰面时,会把感冒传染给碰到的蚂蚁。 请你计算,当...

    蚂蚁算法解决目标问题

    在解决多目标TSP问题时,蚂蚁算法需要进行以下步骤的扩展或调整: 1. 信息素更新规则:在单目标问题中,蚂蚁在路径上留下信息素是为了寻找最短路径。在多目标问题中,可能需要定义一个信息素更新机制,以表示不同...

Global site tag (gtag.js) - Google Analytics