河内塔与相邻的限制

时间:2013-03-21 10:07:57

标签: python algorithm

使用相邻限制解决tower of hanoi。 我试着环顾四周,但我找不到任何导致它。

到目前为止我尝试的是:

def hanoi(n, source, helper, target):
    print "hanoi( ", n, source, helper, target, " called"
    if n>0:
        hanoi(n-1, source, helper, target)
        if source[0]:
             if source[0][-1] == 1:
                 move(source, helper)
                 move(helper, target)
        else:
            move(source, helper)
            hanoi(n-1, target, helper, source)
    hanoi(n-1, helper, target, source)
    hanoi(n-1, source, helper, target)

def move(s, d):
    disk = s[0].pop()
    print "moving " + str(disk) + " from " + s[1] + " to " + d[1]
    d[0].append(disk)

source = ([2,1], "source")
target = ([], "target")
helper = ([], "helper")
hanoi(len(source[0]),source,helper,target)

仅适用于2个磁盘。 感谢

我发现了这个很好的数学解释http://www.cse.cuhk.edu.hk/~chi/csc2110-2009/notes/T10.pdf

1 个答案:

答案 0 :(得分:2)

详细的实施

乍一看,您似乎必须区分可以直接从当前源移动到当前目标的情况,以及必须分两步移动最大磁盘的情况。以下实现可以做到:

class Stack(object):
    def __init__(self, index, name, disks):
        self.index = index
        self.name = name
        self.disks = disks
    def __str__(self):
        return self.name
    def __repr__(self):
        return 'Stack(%r, %r, %r)' % (self.index, self.name, self.disks)
    def is_adjacent(self, other):
        return other.index in (self.index + 1, self.index - 1)
    def push(self, disk):
        assert len(self.disks) == 0 or self.disks[-1] > disk
        self.disks.append(disk)
    def pop(self):
        return self.disks.pop()

class Hanoi(object):

    def __init__(self, n):
        source = Stack(0, "source", range(n, 0, -1))
        helper = Stack(1, "helper", [])
        target = Stack(2, "target", [])
        self.stacks = [source, helper, target]
        self.hanoi(n, source, target)

    def hanoi(self, n, source, target):
        """Move n disks from source to target using remaining stack"""
        helper = self.stacks[3 - source.index - target.index]
        if n == 0:
            return
        if source.is_adjacent(target):
            self.hanoi(n - 1, source, helper)
            self.move(source, target)
            self.hanoi(n - 1, helper, target)
        else:
            assert helper.is_adjacent(source) and helper.is_adjacent(target)
            self.hanoi(n - 1, source, target)
            self.move(source, helper)
            self.hanoi(n - 1, target, source)
            self.move(helper, target)
            self.hanoi(n - 1, source, target)

    def move(self, s, d):
        assert s.is_adjacent(d)
        disk = s.pop()
        print "moving %d from %s to %s" % (disk, s, d)
        d.push(disk)

Hanoi(5)

Stack对象有助于将关于其中一个堆栈的所有内容保存在一起:名称,位置和邻接,以及当前的磁盘序列。如果添加第三个元素来保存该索引,则可以使用元组,但我认为OOP更直观。

Hanoi类将一组堆栈保存在一起。这允许hanoi方法仅指定源和目标,同时推断第三个堆栈。你可以用不同的方式编写代码,但我发现省略帮助程序会使这些递归调用更容易理解:现在,对于单磁盘move和多磁盘hanoi,您指定了源和目标,没有第三个堆栈。

简化空间

现在,如果仔细观察,您会发现递归调用总是针对非相邻堆栈。因此,如果您的堆栈顺序确实是源和目标不相邻,那么所有递归调用都将使用我的代码的else分支,并且您可以缩短事物以避免区分大小并始终使用else 1}}分支。然而,就发生的事情而言,我发现上面更详细的代码更容易理解。