简体   繁体   English

在河内塔中找到第k个举动

[英]to find the k-th move in an Hanoi Tower

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))

why to look at the 2^(n-1) move? 为什么要看2 ^(n-1)的移动? may you explain the code? 您可以解释一下代码吗?

The TL;DR version - it takes 2^(n-1)-1 moves to move a stack of n-1 disks from one position to another, so this code is looking at if you are moving the n-th disk, or moving the stack of n-1 disks on or off of the n-th disk. TL; DR版本-将n-1个磁盘堆栈从一个位置移动到另一位置需要2 ^(n-1)-1个动作,因此此代码正在查看是否要移动第n个磁盘,或者将n-1个磁盘的堆栈移入或移出第n个磁盘。

Full Answer: 完整答案:

Understanding why this code looks at the (n-1)th move in order to determine what the k-th move is requires understanding the basic idea behind moving the entire hanoi tower. 要了解为什么此代码着眼于第(n-1)个移动以便确定第k个移动是什么,需要了解移动整个河内塔的背后的基本思想。

Let's look at an example. 让我们看一个例子。 We have spots A, B, and C, and a tower of 10 disks starting at position A that we want to move to position C. We'll say disk 9 is the largest, next largest is 8, etc. To start off with, it looks like this: 我们有点A,B和C,还有一个10块磁盘的塔,该磁盘要从位置A开始移动到位置C。我们将说磁盘9是最大的,第二个磁盘是8,以此类推。 ,它看起来像这样:

A 9876543210
B
C

So how do we move everything to C? 那么我们如何将所有内容移至C? Well, we need to move the base disk (9) to C, so we move everything else off of it first, like this: 好吧,我们需要将基础磁盘(9)移至C,因此我们首先将其移走,如下所示:

A 9
B 876543210
C

Then we can move disk 9 然后我们可以移动磁盘9

A
B 876543210
C 9

And then move the stack of nine disks back on to disk 9 to end up like this: 然后将九个磁盘的堆栈移回到磁盘9上,最终像这样:

A
B
C 9876543210

Of course, I'm skipping the whole section of how to move the stack of nine disks, but this gives you the basic idea - moving a stack requires moving all but the bottom disk out of the way, then moving the bottom disk, then moving the rest of the disks back on top of it. 当然,我跳过了如何移动九个磁盘的堆栈的整个部分,但这为您提供了基本的思想-移动堆栈需要先移动除底部磁盘以外的所有磁盘,然后再移动底部磁盘,然后再移动将其余磁盘移回其顶部。

So this code is asking "Where are we in this process?" 所以这段代码问“我们在这个过程中在哪里?” If k is equal to 2^(n-1), then we are currently moving the bottom disk of the stack that we are currently trying to move. 如果k等于2 ^(n-1),则我们当前正在移动我们当前要移动的堆栈的底部磁盘。 If k is less than that, we are still in the middle of moving the stack of disks off of the bottom disk. 如果k小于该值,则我们仍处于将磁盘堆栈移出底部磁盘的中间阶段。 If k is greater than that, we are trying to move the stack of disks back onto the bottom disk. 如果k大于该值,我们将尝试将磁盘堆栈移回底部磁盘。 Using my simple example above, if k = 2^(10-1) = 2 ^ 9 = 512, then we are moving disk 9 from A to C. if k is less than 512, then we are still in the process of moving disks 0 through 8 off of disk 9 and into spot B. If k is greater than 512, then we are at k -512 moves into moving disks 0 through 8 from spot B back onto disk 9 in spot C. 使用上面的简单示例,如果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中。

How do we know that 2^(n-1) is the correct value to use? 我们怎么知道2 ^(n-1)是要使用的正确值? Using mathematical induction we can prove that it takes at most (2^n)-1 moves to move a stack of n disks. 使用数学归纳法,我们可以证明最多需要(2 ^ n)-1个动作才能移动n个磁盘的堆栈。 Here is a quick proof: 这是一个快速证明:

Basis for induction: To move a stack of n=1 disks, it takes (2^n)-1=(2^1)-1=1 move - move the only disk. 归纳基础:要移动n = 1个磁盘的堆栈,需要(2 ^ n)-1 =(2 ^ 1)-1 = 1的移动-移动唯一的磁盘。 Inductive step: Assume that it works for n disks (ie that the most efficient way to move the stack takes (2^n)-1 moves). 归纳步骤:假设它适用于n个磁盘(即,最有效的移动堆栈方式需要(2 ^ n)-1个移动)。 Then, to move a stack of n+1 disks, we first use the most efficient way to move the top n disks from off the bottom disk (taking (2^n)-1 moves), move the bottom disk (1 move), then move the other n disks back on top of the bottom disk ((2^n)-1 moves again). 然后,要移动一堆n + 1个磁盘,我们首先使用最有效的方法从底部磁盘移出顶部n个磁盘(采取(2 ^ n)-1个移动),移动底部磁盘(1个移动) ,然后将其他n个磁盘移回底部磁盘的顶部((2 ^ n)-1再次移动)。 So the total number of moves we have taken is (2^n)-1+1+(2^n)-1=2*(2^n)-1=(2^(n+1))-1 moves. 因此,我们采取的总动作数为(2 ^ n)-1 + 1 +(2 ^ n)-1 = 2 *(2 ^ n)-1 =(2 ^(n + 1))-1个动作。

If you haven't seen induction before this probably looks very complicated, but the basic idea is this - since we know it works for one disk, we know it works for two disks. 如果您以前没看过归纳法,这看起来可能很复杂,但是基本思路是这样的-因为我们知道它适用于一个磁盘,所以我们知道它适用于两个磁盘。 Since we now know it works for two disks, it works for three disks. 由于我们现在知道它适用于两个磁盘,因此它适用于三个磁盘。 Since we now know it works for three disks... and so on. 因为我们现在知道它适用于三个磁盘...等等。 The inductive step was for an arbitrary n, so we can apply it as many times as we want. 归纳步骤适用于任意n,因此我们可以根据需要多次应用它。 So for any finite n, we know that the fastest way to move the n disks takes (2^n)-1 moves. 因此,对于任何有限的n,我们都知道,移动n个磁盘的最快方法是(2 ^ n)-1个移动。

So now the question is, on which move is the nth disk moved? 因此,现在的问题是,第n个磁盘在哪个磁盘上移动? On the (2^(n-1))-1-th move, we can finish moving the stack of n-1 disks on top of the bottom disk. 在第(2 ^(n-1))-1个步骤中,我们可以完成将n-1个磁盘堆栈移至底部磁盘顶部的操作。 Then, on the (2^(n-1))-1+1=2^(n-1)-th move, we are able to move the bottom disk. 然后,在第(2 ^(n-1))-1 + 1 = 2 ^(n-1)次移动中,我们可以移动底部磁盘。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM