7-17 汉诺塔的非递归实现 (25 分)
问题描述:
借助堆栈以非递归(循环)方式求解汉诺塔的问题(n, a, b, c),即将N个盘子从起始柱(标记为“a”)通过借助柱(标记为“b”)移动到目标柱(标记为“c”),并保证每个移动符合汉诺塔问题的要求。
输入格式:
输入为一个正整数N,即起始柱上的盘数。
输出格式:
每个操作(移动)占一行,按柱1 -> 柱2的格式输出。
输入样例:
3
输出样例:
a -> c
a -> b
c -> b
a -> c
b -> a
b -> c
a -> c
提交结果
分析
- 本题我本是没有思路的,并不是很懂汉诺塔的算法逻辑,查阅一部分资料以后,大致明白了算法怎样进行,但是原理还不是很清楚,大家可以参考汉诺塔算法。
- 看完以后,还是为了图方便,我用了python写代码,但是,写完以后,发现最后一组测试数据超时(python的硬伤),我尽力进行了优化,但是还是超时,没办法,决定用C语言写。
- 看了看网上的代码,大多都是C++写的,奈何我菜,没学过,看不懂,只能一比一把我python代码修改成了C的代码,最后也是通过了测试。
代码
#include<stdio.h>
#include<string.h>
void move(int pos1, int data[3][30], int pos2, char l[], int pos[])
{
int b = data[pos1][pos[pos1]]; //获取两个柱子顶部元素
int c = data[pos2][pos[pos2]];
if ((b < c || c == 0) && b != 0) { //第一个柱子小,或者第二个柱子空时,将第一个柱子顶部盘子转移到第二个
data[pos2][++pos[pos2]] = b;
pos[pos1]--;
printf("%c -> %c\n", l[pos1], l[pos2]);
}
else if ((b > c || b == 0) && c != 0) { //原理同上
data[pos1][++pos[pos1]] = c;
pos[pos2]--;
printf("%c -> %c\n", l[pos2], l[pos1]);
}
}
int main()
{
int pillars[3][30] = { 0 }, i, pos[3] = { 0 }, n, pos_key = 0; //储存三个柱子上面的盘子序号、三个柱子的最后一个元素的位置、‘1’号盘子所在的位置
char str[10]; //三个柱子的代号
scanf("%d", &n);
strcpy(str, n % 2 ? "acba" : "abca"); //偶数abc;奇数acb
int flag = 2 - n % 2; //根据输入的奇偶判断目标柱子的位置
for (i = 0; i < n; i++)
pillars[0][i + 1] = n - i;
pos[0] = n; //初始化‘a’柱
while (n != 0) { //输入0时不做任何输出
printf("%c -> %c\n", str[pos_key], str[pos_key + 1]); //转移‘1’盘子
pos[pos_key]--; //存放‘1’的柱子计数减一
pos_key = (pos_key + 1) % 3; //‘1’的位置加一,并取余防止溢出
pillars[pos_key][++pos[pos_key]] = 1; //被转移柱子计数加一
if (pos[flag] == n) break; //如果目标柱子已经摆满所有盘子,即达到目标,停止循环
int p1 = (pos_key + 1) % 3, p2 = (pos_key + 2) % 3;
move(p1, pillars, p2, str, pos); //将除‘1’所在柱子外的两个柱子的顶部最小的盘子转移到另一个柱子
}
return 0;
}
另附:
(把python代码也贴一贴吧,想看的可以看一下)
def move(pos1, data, pos2, l):
x1, x2 = l[pos1], l[pos2]
b = data[pos1][len(data[pos1])-1]
c = data[pos2][len(data[pos2])-1]
if (b < c or c == 0) and b != 0:
data[pos2].append(data[pos1].pop())
print(x1,"->",x2)
elif (b > c or b == 0) and c != 0:
data[pos1].append(data[pos2].pop())
print(x2,"->",x1)
n = int(input())
pillars = [[0],[0],[0]]
l = ['a','b','c','a']
for i in range(n):
pillars[0].append(n-i)
if n%2 == 1:
l = ['a','c','b','a']
flag = 2 - n%2
pos_1 = 0
while n != 0:
pillars[pos_1].remove(1)
print(l[pos_1], "->", l[pos_1+1])
pos_1 = (pos_1+1)%3
pillars[pos_1].append(1)
if len(pillars[flag]) - n-1 == 0:
break
move((pos_1+1)%3, pillars, (pos_1+2)%3, l)
由于是同样的方法,我就不给python代码注释了。