在河内塔找到第k个动作

时间:2014-02-13 18:34:47

标签: python python-3.x towers-of-hanoi

def hanoi_move ( start , via , target ,n ,k ):
    """ finds the k-th move in an Hanoi Towers instance
    with n discs """
    if n <=0:
        return "zero or fewer disks"
    elif k <=0 or k >=2** n or type(k )!= int :
        return "number of moves is illegal"
    elif k ==2**( n -1):
        return str . format ("disk {} from {} to {}",n , start , target )
    elif k <2**( n -1):
         return hanoi_move ( start , target , via ,n -1 , k)
    else:
        return hanoi_move ( via , start , target ,n -1 ,k -2**( n -1))

为什么要看2 ^(n-1)动作?你能解释一下代码吗?

1 个答案:

答案 0 :(得分:3)

TL; DR版本 - 需要2 ^(n-1)-1次移动才能将一堆n-1个磁盘从一个位置移动到另一个位置,因此这段代码会查看您是否正在移动第n个磁盘磁盘,或者在第n个磁盘上打开或关闭n-1个磁盘的堆栈。

完整答案:

理解为什么这段代码看第(n-1)次移动以确定第k次移动需要了解移动整个河内塔背后的基本思想。

让我们看一个例子。我们有A,B和C点,以及从A位开始的10个盘的塔,我们想要移动到位置C.我们会说盘9是最大的,下一个是8,等等。 ,它看起来像这样:

A 9876543210
B
C

那么我们如何将一切都移到C?好吧,我们需要将基础磁盘(9)移动到C,所以我们首先将其他所有内容移出,如下所示:

A 9
B 876543210
C

然后我们可以移动磁盘9

A
B 876543210
C 9

然后将九个磁盘的堆栈重新移回磁盘9,最终结果如下:

A
B
C 9876543210

当然,我正在跳过如何移动九个磁盘堆栈的整个部分,但这给出了基本的想法 - 移动堆栈需要移动除底部磁盘之外的所有磁盘,然后移动底部磁盘,然后将其余磁盘移回其上。

所以这段代码问“我们在这个过程中的哪个位置?”如果k等于2 ^(n-1),那么我们当前正在移动我们当前正在尝试移动的堆栈的底部磁盘。如果k小于该值,我们仍处于将磁盘堆栈从底部磁盘移出的过程中。如果k大于此值,我们会尝试将磁盘堆栈移回底部磁盘。使用上面的简单示例,如果k = 2 ^(10-1)= 2 ^ 9 = 512,那么我们将磁盘9从A移动到C.如果k小于512,则我们仍在将磁盘0到8从磁盘9移到B点。如果k大于512,那么我们在k - 512移动到移动磁盘0到8从现场B回到现场C的磁盘9上。

我们怎么知道2 ^(n-1)是正确使用的值?使用mathematical induction我们可以证明移动一堆n个磁盘最多需要(2 ^ n)-1次移动。这是一个快速证明:

感应的基础:要移动一堆n = 1个磁盘,需要(2 ^ n)-1 =(2 ^ 1)-1 = 1移动 - 移动唯一的磁盘。 归纳步骤:假设它适用于n个磁盘(即移动堆栈的最有效方式是(2 ^ n)-1次移动)。然后,为了移动一堆n + 1个磁盘,我们首先使用最有效的方法将前n个磁盘从底部磁盘移开(取(2 ^ n)-1个移动),移动底部磁盘(1个移动) ,然后将其他n个磁盘移回底部磁盘顶部((2 ^ n)-1再次移动)。所以我们采取的移动总数是(2 ^ n)-1 + 1 +(2 ^ n)-1 = 2 *(2 ^ n)-1 =(2 ^(n + 1)) - 1次移动

如果您之前没有看过感应可能看起来很复杂,但基本的想法是这样的 - 因为我们知道它适用于一个磁盘,我们知道它适用于两个磁盘。由于我们现在知道它适用于两个磁盘,因此适用于三个磁盘。因为我们现在知道它适用于三个磁盘......等等。归纳步骤适用于任意n,因此我们可以根据需要多次应用它。因此,对于任何有限n,我们知道移动n个磁盘的最快方法是(2 ^ n)-1次移动。

所以现在的问题是,第n个磁盘移动了哪一步?在(2 ^(n-1)) - 1次移动中,我们可以完成在底部磁盘顶部移动n-1个磁盘的堆栈。然后,在(2 ^(n-1)) - 1 + 1 = 2 ^(n-1)次移动中,我们可以移动底部磁盘。