问题:
In the classic problem of the Towers of Hanoi, you have 3 rods and N disks of different sizes which can slide onto any tower. The puzzle starts with disks sorted in ascending order of size from top to bottom (e.g., each disk sits on top of an even larger one). You have the following constraints:
- Only one disk can be moved at a time.
- A disk is slid off the top of one rod onto the next rod.
- A disk can only be placed on top of a larger disk.
Write a program to move the disks from the first rod to the last using Stacks
分析:这道题可以用两种方法解决:递归;非递归。首先讨论递归。
要用递归解决一道题,就要先找到一个subproblem。首先看problem是什么。我们有三个柱子,比如我们叫他们src,bri,dst。我们的目标是把n个盘子从src通过bri转移到dst,并且过程中不能有大的盘子在小的上面。那么为了实现这个目的,我们一定会达到下面这样一种状态,即:最大的盘子还在src上,其余n-1个盘子在bri上,dst上是空的,即:(n, 1~n-1, 0)。在这个状态下,把最大的盘子从src移动到dst,然后再以bri为src,src为bri,把剩下的n-1个盘子移动到dst。那么这就是一个size为n-1的subproblem。所以代码如下:
void hanoi_recursion (int n, char start, char mid, char end) {
if (n == 1)
cout << "Move disk " << n << " from " << start " to " << end;
else {
hanoi_recursion(n-1, start, end, mid);
cout << "Move disk " << n << " from " << start " to " << end;
hanoi_recursion(n-1, mid, start, end);
}
}
题目中要求的是用stack。其实严格来说,递归也是用了stack,只不过没有显性地使用这个数据结构,而是在内存中压入栈。
现在介绍非递归的方法。显然,需要用到stack数据结构。
我们的初始状态是:(1~n, 0, 0); 我们的目标状态是(0, 0, 1~n)。那么从初始状态到目标状态,肯定要经过如下几个状态:
1. (1~n, 0, 0)
2. (n, 1~n-1, 0)
3. (0, 1~n-1, 0)
4. (0, 0, 1~n)
这和我们上面的分析是一样的。
我们定义一个数据结构node如下:
struct node {
int start;
int end;
char src, bri, dst;
node (int st, int en, int sc, int br, int ds) : start(st), end(en), src(sc), bri(br), dst(ds) {}
};
其中,start表示src根柱子上的第一个盘子;end表示src这根柱子上的最后一个盘子。从start到end就是我们需要从src移动到dst的盘子。那么我们的初始状态就可以用一个node来表示,其中start=1, end = n, src = src, bri = bri, dst = dst。由于我们用的是stack,所以先进后出,所以我们需要把表示从状态3到状态4的node推进去;然后是表示从状态2到状态3的;最后是是表示从状态1到状态2的。所以代码如下:
void hanoi_iterative (int n, char src, char bri, char dst) {
stack<node> nodeStack;
nodeStack.push(node(1, n, src, bri, dst));
while (!nodeStack.empty()) {
node curr = nodeStack.top();
nodeStack.pop();
if (curr.start != curr.end) {
nodeStack.push(node(curr.start, curr.end - 1, curr.bri, curr.src, curr.dst));
nodeStack.push(node(curr.end, curr.end, curr.src, curr.bri, curr.dst));
nodeStack.push(node(curr.start, curr.end - 1, curr.src, curr.dst, curr.bri));
}
else
cout << "Move disk " << curr.start << " from " << curr.src << " to " << curr.dst << endl;
}
}