Tower of Hanoi 汉诺塔以及汉诺塔限制版和谢尔宾斯基三角形的关系

原版汉诺塔问题

Tower of Hanoi 汉诺塔以及汉诺塔限制版和谢尔宾斯基三角形的关系_第1张图片

二进制表示当前情况:000

游戏玩法:

将A柱子上的圆盘全部移动至B或C,一次移动一个圆盘,且大盘必须位于小盘之下(这里对游戏玩法不做过多描述)。

过程

定义函数

//A移动至C通过B,这里的通过意思是后面需要通过与B交换,即借助的意思
//n=1时,这不需要借助B,直接A移动至C
honoi(int n, char A, char B, char C);

3个圆盘(大中小3盘)为例,设想一下,从最后的情况考虑,即A大盘移动至C
Tower of Hanoi 汉诺塔以及汉诺塔限制版和谢尔宾斯基三角形的关系_第2张图片

二进制表示当前情况:011

可以看到,要使A大盘移动至C,需要将A上中盘和小盘移动至B,即A柱(n-1)先移动至B
怎么实现,我们把B柱看成C柱,问题被分解成2阶汉诺塔问题:
Tower of Hanoi 汉诺塔以及汉诺塔限制版和谢尔宾斯基三角形的关系_第3张图片

二进制表示当前情况:00

所以在代码中需要体现B柱与C柱交换

//可以理解为A上n-1个盘移动至B,通过C(函数定义)
//想象一下当n-1为1时,A上1个盘可直接移至B
//当n-1>1时,A上n-1个盘移至B,不可直接移动,需要借助C
honoi(n - 1, A, C, B);

然后A大盘移动至C

Tower of Hanoi 汉诺塔以及汉诺塔限制版和谢尔宾斯基三角形的关系_第4张图片

二进制表示当前情况:100

移动后现在要做的就是B上中盘和小盘要移动至C
那要怎么移动呢?因为C盘上的大盘是最大的盘,所有盘都可以放在它上面,我们就当它不存在。
现在的问题就被分解成2阶汉诺塔问题,我们可以这样理解,把B看做A,A看做B,如下图
Tower of Hanoi 汉诺塔以及汉诺塔限制版和谢尔宾斯基三角形的关系_第5张图片

二进制表示当前情况:00

所以在代码中需要体现A柱与B柱交换

//可以理解为B上n-1个盘移动至C,通过A(函数定义)
honoi(n - 1, B, A, C);

B上中盘和小盘要移动至C后
Tower of Hanoi 汉诺塔以及汉诺塔限制版和谢尔宾斯基三角形的关系_第6张图片

二进制表示当前情况:111

问题分解到二阶;再分解至一阶,到达递归出口,程序结束。

Code(c++)

#include
using namespace std;
int honoi(int n, char A, char B, char C) {
	if (n == 1) {
		cout << A << " -> " << C << endl;
		return 1;
	} else {
		int ab = honoi(n - 1, A, C, B);
		cout << A << " -> " << C << endl;
		int bc = honoi(n - 1, B, A, C);
		return ab + bc+1;
	}
}
int main() {
	int n;
	cin >> n;
	int c = honoi(n, 'A', 'B', 'C');
	cout << c << endl;
}

观察二进制表示的情况,可以发现有趣的想象,二进制的进位状态与汉诺塔圆盘移动情况符合,且从低位到高位表示从小到大盘移动情况

初始:000
A -> C:001
A -> B:010
C -> B:011
A -> C:100
B -> A:101
B -> C:110
A -> C:111
移动7次

为什么会这样?道理都懂,就是解释不了-_-
因此求移动次数,就等于 2^n - 1,且是最优解

限制版汉诺塔问题

游戏玩法:

将A柱子上的圆盘全部移动至B或C,一次移动一个圆盘(只能移动到隔壁的柱子,如A->B符合要求 A->C不符合),且大盘必须位于小盘之下(这里对游戏玩法不做过多描述)。

基本思路与原版汉诺塔一样,只是移动时会多增加一步,限制条件导致(列如:A到C必须经过B)
具体描述以后有时间填,以下是代码:

Code(c++)

#include
using namespace std;
long long hanoi(int n,char A,char B,char C) {
	if (n == 1) {
		cout << A << "->" << B << endl;
		cout << B << "->" << C << endl;
		return 2;
	} else {
		long long atoc = hanoi(n - 1, A, B, C);//A(n-1) -> C by B
		cout << A << "->" << B << endl;//An -> B
		long long ctoa = hanoi(n - 1, C, B, A);//C(n-1) -> A by B
		cout << B << "->" << C << endl;//Bn -> C
		long long atoc2 = hanoi(n - 1, A, B, C);//A(n-1) -> Cn by B
		return atoc + ctoa + atoc2 + 2;
	}
}
int main() {
	int n;
	cin >> n;
	long long ans = hanoi(n, 'A', 'B', 'C');
	printf("%lld\n", ans);
	return 0;
}

限制版可以发现有趣的想象,三进制的进位状态也与汉诺塔圆盘移动情况符合

初始:000
A->B:001
B->C:002
A->B:010
C->B:011
B->A:012
B->C:020
A->B:021
B->C:022
A->B:100
C->B:101
B->A:102
C->B:110
A->B:111
B->C:112
B->A:120
C->B:121
B->A:122
B->C:200
A->B:201
B->C:202
A->B:210
C->B:211
B->A:212
B->C:220
A->B:221
B->C:222
移动26次数

因此求移动次数,就等于 3^n - 1,且是最优解

限制版汉诺塔的高级玩法 谢尔宾斯基三角形

3阶汉诺塔限制版所有情况构成谢尔宾斯基三角形

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vqqRDSta-1574139448924)(http://zig.kim/uploads/markdown/20190306-222024-905.png)]

按照解汉诺塔的顺序,可以遍历谢尔宾斯基三角形,非常有趣,数学之美 m_m

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fEtD31X2-1574139448925)(http://zig.kim/uploads/markdown/20190306-222358-148.png)]

更高阶的谢尔宾斯基三角形(分形)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9K1OM1G2-1574139448925)(http://zig.kim/uploads/markdown/20190306-221650-449.png)]

以上三张截图来自视频[Binary, Hanoi, and Sierpinski, part 2]
有兴趣可查看youtube原视频 or bilibili 中文字幕视频

你可能感兴趣的:(算法基础)