经典汉诺塔问题
汉诺塔问题是经典的可以用递归解决的问题。
汉诺塔(Hanoi)游戏规则如下:在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如下图)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。计算需要移动的次数。
我们先来对汉诺塔的步数进行一下递推。
对于 n n n个盘子,我们可以把它分成 n − 1 n-1 n−1个盘子和最后一个大盘子。设 F ( n ) F(n) F(n)为移动所需步数,那么对于 n n n个盘子来说所做的事情就是
- 将 n − 1 n-1 n−1个盘子从A柱借助C柱移动到B柱,这一过程移动的步数为 F ( n − 1 ) F(n-1) F(n−1)
- 将大盘子从A柱直接移动到C柱,此时需要1步。
- 将 n − 1 n-1 n−1个盘子从B柱借助A柱移动到C柱,此时需要的步数仍为 F ( n − 1 ) F(n-1) F(n−1)。
综合以上分析, F ( n ) = 2 F ( n − 1 ) + 1 F(n)=2F(n-1)+1 F(n)=2F(n−1)+1。对两边同时加上1可以凑成一个等比数列,然后就可以求出其通项公式。
完整C++代码:
#include <iostream>
#include <cmath>
using namespace std;
void Hanoi(char a, char b, char c, int n) // 把n个盘从a经过b移动到c
{
if (n == 0)
return;
Hanoi(a, c, b, n - 1);
cout << a << " -> " << c << endl;
Hanoi(b, a, c, n - 1);
}
int main()
{
int n;
cin >> n;
Hanoi('a', 'b', 'c', n);
}
如果要计算移动的次数可以定义一个全局变量ans来保存:
#include <iostream>
#include <cmath>
using namespace std;
int ans = 0;
void Hanoi(char a, char b, char c, int n) // 把n个盘从a经过b移动到c
{
if (n == 0)
return;
Hanoi(a, c, b, n - 1);
ans++;
cout << a << " -> " << c << endl;
Hanoi(b, a, c, n - 1);
}
int main()
{
int n;
cin >> n;
Hanoi('a', 'b', 'c', n);
cout << ans;
}
输入:3
输出:
改后的汉诺塔问题
改进的汉诺塔问题如下:
汉诺塔(Hanoi)游戏规则如下:在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如下图)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,且限定圆盘只能够移动到相邻的柱子,即A柱子上的圆盘只能够移动到B,B柱子上的圆盘只能够移动到A或者C,C同理。并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。计算需要移动的次数。
我们先来对改后的汉诺塔的步数进行一下递推。
对于 n n n个盘子,我们还是可以把它分成 n − 1 n-1 n−1个盘子和最后一个大盘子。设 F ( n ) F(n) F(n)为移动所需步数,那么对于 n n n个盘子来说所做的事情就是
- 将 n − 1 n-1 n−1个盘子从A柱借助B柱移动到C柱,这一过程移动的步数为 F ( n − 1 ) F(n-1) F(n−1)
- 将大盘子从A柱直接移动到B柱,此时需要1步。
- 将 n − 1 n-1 n−1个盘子从C柱借助B柱移动到A柱,此时需要的步数仍为 F ( n − 1 ) F(n-1) F(n−1)。
- 将大盘子从B柱直接移动到C柱,此时需要1步。
- 将 n − 1 n-1 n−1个盘子从A柱借助B柱移动到C柱,此时需要的步数仍为 F ( n − 1 ) F(n-1) F(n−1)。
综合以上分析, F ( n ) = 3 F ( n − 1 ) + 2 F(n)=3F(n-1)+2 F(n)=3F(n−1)+2。对两边同时加上1可以凑成一个等比数列,然后就可以求出其通项公式。
完整C++代码:
#include <iostream>
#include <cmath>
using namespace std;
void Hanoi(char a, char b, char c, int n) // 把n个盘从a经过b移动到c
{
if (n == 0)
return;
Hanoi(a, b, c, n - 1);
cout << a << " -> " << b << endl;
Hanoi(c, b, a, n - 1);
cout << b << " -> " << c << endl;
Hanoi(a, b, c, n - 1);
}
int main()
{
int n;
cin >> n;
Hanoi('a', 'b', 'c', n);
}
如果要计算移动的次数可以定义一个全局变量ans来保存:
#include <iostream>
#include <cmath>
using namespace std;
int ans = 0;
void Hanoi(char a, char b, char c, int n) // 把n个盘从a经过b移动到c
{
if (n == 0)
return;
Hanoi(a, b, c, n - 1);
ans++;
cout << a << " -> " << b << endl;
Hanoi(c, b, a, n - 1);
ans++;
cout << b << " -> " << c << endl;
Hanoi(a, b, c, n - 1);
}
int main()
{
int n;
cin >> n;
Hanoi('a', 'b', 'c', n);
cout << ans;
}
输入:3
输出: