四个柱子的汉诺塔
和三个柱子的最初的汉诺塔很类似,只是多了一个柱子,相当于缓存区大了一些,处理的速度自然快了一些。
粗略的C代码(并没有使先移动到第四根柱子上面的圆盘的数量是最优):
#include <stdio.h>
int count = 0;
void hanoi (char s, char t1, char t2, char t, int n)
{
if (0 == n)
return;
if (1 == n)
{
printf ("%c -> %c\n", s, t);
printf("%d\n", ++count);
return;
}
hanoi (s, t2, t, t1, n - 2); // 先将 n - 2 个圆盘从 s 移动到 t1
printf ("%c -> %c\n", s, t2); // 将此时最上面的圆盘移动到 t2 上
printf("%d\n", ++count);
printf ("%c -> %c\n", s, t); // 将剩下的最后一个圆盘移动到 t 上
printf("%d\n", ++count);
printf ("%c -> %c\n", t2, t); // 将 t2 上的圆盘移动到 t 上
printf("%d\n", ++count);
hanoi (t1, s, t2, t, n - 2); // 将 t1 上的圆盘移动到 t上,此时,s 和 t2 成了辅助的柱子
return;
}
int main ()
{
hanoi ('A', 'B', 'C', 'D', 8);
return (0);
}
这个版本就是简单地先将 n - 2 个圆盘放到第 4 个柱子上,然后将剩下的两个圆盘转移到目标柱子上,如此递归。所以并不是最优解。
关于对于不同的圆盘的数量,如何控制率先移动到第四个柱子的圆盘的数量,目前只是想到了一种很笨的方法,就是遍历所有的可能,然后找出最优解,然后存储到数组中,然后再再递归调用移动圆盘的函数的时候进行控制(移动圆盘的函数暂时还没有实现)。
由于样本数据取到了64个圆盘,最后的数据会比较大,所以选择了不限数据大小的Python,进行确定四个柱子的情况下的最少移动的次数和最优的率先移动到第 4 根柱子的圆盘的数量。
Python代码:
# 最终只在列表中存储64个数据,第一个数据舍弃,是为了序列能够从1开始
# 存储三个柱子的情况,然后初始化
ThreeHanoi = []
ThreeHanoi.append(0)
ThreeHanoi.append(1)
for i in range(2, 65): # 只需要再添加 63 个数据,就凑足了 65 了数据,实际有效的数据只有64个,第一个数据只是为了占位
ThreeHanoi.append(2 * ThreeHanoi[i - 1] + 1)
# 存储四个柱子的情况,然后初始化
count4 = 0
FourHanoi = []
FourHanoi.append(0) # 占位
FourHanoi.append(1) # 只有一个圆盘需要移动 1 次
FourHanoi.append(3) # 有两个圆盘的情况下需要移动 3 次
StoreJ = []
StoreJ.append(0)
StoreJ.append(0)
StoreJ.append(0)
for i in range(3, 65): # 还需要再添加 62 个数据
min = ThreeHanoi[i]
flag_j = 0
for j in range(1, i):
count4 = 2 * FourHanoi[j] + ThreeHanoi[i - j]
if count4 < min:
min = count4
flag_j = j
FourHanoi.append(min)
StoreJ.append(flag_j)
print(ThreeHanoi)
print(FourHanoi)
print(StoreJ)
结果:
[0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647, 4294967295, 8589934591, 17179869183, 34359738367, 68719476735, 137438953471, 274877906943, 549755813887, 1099511627775, 2199023255551, 4398046511103, 8796093022207, 17592186044415, 35184372088831, 70368744177663, 140737488355327, 281474976710655, 562949953421311, 1125899906842623, 2251799813685247, 4503599627370495, 9007199254740991, 18014398509481983, 36028797018963967, 72057594037927935, 144115188075855871, 288230376151711743, 576460752303423487, 1152921504606846975, 2305843009213693951, 4611686018427387903, 9223372036854775807, 18446744073709551615]
[0, 1, 3, 5, 9, 13, 17, 25, 33, 41, 49, 65, 81, 97, 113, 129, 161, 193, 225, 257, 289, 321, 385, 449, 513, 577, 641, 705, 769, 897, 1025, 1153, 1281, 1409, 1537, 1665, 1793, 2049, 2305, 2561, 2817, 3073, 3329, 3585, 3841, 4097, 4609, 5121, 5633, 6145, 6657, 7169, 7681, 8193, 8705, 9217, 10241, 11265, 12289, 13313, 14337, 15361, 16385, 17409, 18433]
[0, 0, 0, 1, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 10, 10, 11, 12, 13, 14, 15, 15, 16, 17, 18, 19, 20, 21, 21, 22, 23, 24, 25, 26, 27, 28, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 45, 46, 47, 48, 49, 50, 51, 52, 53]
为方便观察,下面将数据以“盘数 : 最少移动次数,最合适的率先移动的盘数”列出:
1 : 1 , 0
2 : 3 , 0
3 : 5 , 1
4 : 9 , 1
5 : 13 , 2
6 : 17 , 3
7 : 25 , 3
8 : 33 , 4
9 : 41 , 5
10 : 49 , 6
11 : 65 , 6
12 : 81 , 7
13 : 97 , 8
14 : 113 , 9
15 : 129 , 10
16 : 161 , 10
17 : 193 , 11
18 : 225 , 12
19 : 257 , 13
20 : 289 , 14
21 : 321 , 15
22 : 385 , 15
23 : 449 , 16
24 : 513 , 17
25 : 577 , 18
26 : 641 , 19
27 : 705 , 20
28 : 769 , 21
29 : 897 , 21
30 : 1025 , 22
31 : 1153 , 23
32 : 1281 , 24
33 : 1409 , 25
34 : 1537 , 26
35 : 1665 , 27
36 : 1793 , 28
37 : 2049 , 28
38 : 2305 , 29
39 : 2561 , 30
40 : 2817 , 31
41 : 3073 , 32
42 : 3329 , 33
43 : 3585 , 34
44 : 3841 , 35
45 : 4097 , 36
46 : 4609 , 36
47 : 5121 , 37
48 : 5633 , 38
49 : 6145 , 39
50 : 6657 , 40
51 : 7169 , 41
52 : 7681 , 42
53 : 8193 , 43
54 : 8705 , 44
55 : 9217 , 45
56 : 10241 , 45
57 : 11265 , 46
58 : 12289 , 47
59 : 13313 , 48
60 : 14337 , 49
61 : 15361 , 50
62 : 16385 , 51
63 : 17409 , 52
64 : 18433 , 53
这三行数据依次是三个柱子时的最少移动次数,四个柱子的最少移动次数和四个柱子时率先移动到第四根柱子的最优数量。