首页 > 试题广场 >

用栈来求解汉诺塔问题

[编程题]用栈来求解汉诺塔问题
  • 热度指数:2314 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
汉诺塔问题比较经典,这里修改一下游戏规则:现在限制不能从最左侧的塔直接移动到最右侧,也不能从最右侧直接移动到最左侧,而是必须经过中间。求当塔有n层的时候,打印最优移动过程和最优移动总步数。

输入描述:
输入一个数n,表示塔层数


输出描述:
按样例格式输出最优移动过程和最优移动总步数
示例1

输入

2

输出

Move 1 from left to mid
Move 1 from mid to right
Move 2 from left to mid
Move 1 from right to mid
Move 1 from mid to left
Move 2 from mid to right
Move 1 from left to mid
Move 1 from mid to right
It will move 8 steps.

说明

当塔数为两层时,最上层的塔记为1,最下层的塔记为2

备注:
《程序员代码面试》Python题解
递归代码
# 递归求解
def hanoiProblem(num, left, mid, right):
    # num是需要移动的盘子数
    # left,mid,right是三座塔
    # 如果盘子数小于等于0
    if num < 1:
        # 移动步数是0
        return 0
    # 其它情况调用递归函数进行求解
    return process(num, left, mid, right, left, right)


# 汉诺塔递归求解函数
def process(num, left, mid, right, from_which, to):
    """
    :param num: 移动的盘子数
    :param left: 左塔
    :param mid: 中塔
    :param right: 右塔
    :param from_which: 盘子现在在哪座塔上
    :param to: 要移动到哪里
    :return: 最少移动步数
    """
    # 递归终止条件
    # 只剩一个盘子
    if num == 1:
        # 第一种情况
        # 从中塔到两端
        # 或者从两端到中塔
        if from_which == 'mid'&nbs***bsp;to == 'mid':
            print("Move 1 from {} to {}".format(from_which, to))
            return 1
        # 第二种情况
        # 从左塔到右塔
        # 或者从右塔到左塔
        else:
            print("Move 1 from {} to {}".format(from_which, mid))
            print("Move 1 from {} to {}".format(mid, to))
            return 2
    # 递归体
    # 第一种情况
    # 从中塔到两端
    # 或者从两端到中塔
    if from_which == 'mid'&nbs***bsp;to == 'mid':
        # 需要三步操作
        # 先将num-1个盘子从from_which移动到除了中塔的另外一座塔上
        another = right if (from_which == 'left'&nbs***bsp;to == 'left') else left
        part1 = process(num - 1, left, mid, right, from_which, another)
        # 将第num个盘子从from_which移动到to
        print("Move {} from {} to {}".format(num, from_which, to))
        part2 = 1
        # 将num-1个盘子从另外一座塔移动到to
        part3 = process(num - 1, left, mid, right, another, to)
        # 最少移动步数
        return part1 + part2 + part3
    # 第二种情况
    # 从左塔移动到右塔
    # 或者从右塔移动到中塔
    else:
        # 分为5步
        # 先将num-1个盘子从from_which移动到to
        part1 = process(num - 1, left, mid, right, from_which, to)
        # 将第num个盘子从from_which移动到中塔
        print("Move {} from {} to {}".format(num, from_which, mid))
        part2 = 1
        # 将num-1个盘子从to移动到from_which
        part3 = process(num - 1, left, mid, right, to, from_which)
        # 将第num个盘子从中塔移动到to
        print("Move {} from {} to {}".format(num, mid, to))
        part4 = 1
        # 最后将num-1个盘子从from_which移动到to
        part5 = process(num - 1, left, mid, right, from_which, to)
        # 最少移动步数
        return part1 + part2 + part3 + part4 + part5


# 移动的盘子数
n = int(input())
step = hanoiProblem(n, 'left', 'mid', 'right')
print("It will move {} steps.".format(step))

用栈实现的代码
# 定义操作列表
# 分别是:
# 不做任何操作
# 左塔到中塔
# 中塔到左塔
# 中塔到右塔
# 右塔到中塔
action = ['No', 'LToM', 'MToL', 'MToR', 'RToM']


# 用栈求解汉诺塔问题
def hanoiProblem(num, left, mid, right):
    """
    :param num:移动的盘子数
    :param left:左塔
    :param mid:中塔
    :param right:右塔
    :return:最少移动步数
    """
    # 用列表模拟栈
    # 左塔
    ls = []
    # 中塔
    ms = []
    # 右塔
    rs = []
    # 将最大值加入栈中
    # 方便后面处理
    max_value = 10 ** 10
    ls.append(max_value)
    ms.append(max_value)
    rs.append(max_value)
    # 向右塔中加入num个盘子
    for i in range(num, 0, -1):
        ls.append(i)
    # 初始化操作序列记录
    record = [action[0]]
    # 初始化最少移动步数
    step = 0
    # 当num座塔没有完全被移动到右塔上时
    while len(rs) != num + 1:
        # 分别进行四种操作的试探
        step += fstackTotstack(record, action[2], action[1], ls, ms, left, mid)
        step += fstackTotstack(record, action[1], action[2], ms, ls, mid, left)
        step += fstackTotstack(record, action[4], action[3], ms, rs, mid, right)
        step += fstackTotstack(record, action[3], action[4], rs, ms, right, mid)
    return step


# 出栈、入栈操作
def fstackTotstack(record, pre_action, now_action, fstack, tstack, from_which, to):
    """
    :param record: 操作序列记录
    :param pre_action: 上个操作
    :param now_action:当前的操作
    :param fstack:出栈
    :param tstack:入栈
    :param from_which:出塔
    :param to:入塔
    :return:移动次数
    """
    # 如果满足操作条件
    if record[0] != pre_action and fstack[-1] < tstack[-1]:
        # 入栈
        tstack.append(fstack.pop())
        print("Move {} from {} to {}".format(tstack[-1], from_which, to))
        # 更新记录
        record[0] = now_action
        return 1
    return 0


n = int(input())
step = hanoiProblem(n, 'left', 'mid', 'right')
print("It will move {} steps.".format(step))


发表于 2021-12-26 08:08:22 回复(1)

问题信息

上传者:小小
难度:
1条回答 3967浏览

热门推荐

通过挑战的用户

查看代码