1. 程式人生 > 實用技巧 >四個柱子的漢諾塔

四個柱子的漢諾塔

和三個柱子的最初的漢諾塔很類似,只是多了一個柱子,相當於快取區大了一些,處理的速度自然快了一些。

粗略的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]

這三行資料依次是三個柱子時的最少移動次數,四個柱子的最少移動次數和四個柱子時率先移動到第四根柱子的最優數量。