24h購物| | PChome| 登入
2012-10-03 22:44:50| 人氣71,071| 回應2 | 上一篇 | 下一篇

[2013/10更新][資料結構] 誰說非遞迴河內塔不好寫的 ?

推薦 4 收藏 0 轉貼0 訂閱站台

Background.
上資料結構光是一個 ADT 定義就可以講了很久, 定義相信是很重要的一環, 不過我聽了一節課的陣列定義也是有點累了, 隔了一個禮拜過後, 換了個遞迴講, 光是費氏+階乘的遞迴展開就一節課多了, 之後講了遞迴必須的堆疊定義, Oh, my god, 一講到非遞迴河內塔不好寫, 我整個賭氣了

#include <stdio.h>
void hanoi(int n, char A, char B, char C) {
    if(n == 1)
        printf("Move %d from %c to %c\n", n, A, C);
    else{
        hanoi(n - 1, A, C, B);
        printf("Move %d from %c to %c\n", n, A, C);
        hanoi(n - 1, B, A, C);
    }
}
int main() {
    int n;
    while(scanf("%d", &n) == 1)
        hanoi(n, 'A', 'B', 'C');
    return 0;
}


數學解 AB, AC, BA, BC, CA, CB 0~5

「經過何錦文教授的指導,我大致上可以說一說這個解法怎麼來的,首先很明顯的數字移動部分來自於遞迴,接著狀態轉移的部分,可以從n的奇偶數下手發現,上部份轉換成下部份的狀態可以從遞迴中察覺。如果要證明的話可以從數學歸納法下手證明與原始遞迴一樣」-2012/10/18
「更有一個不用遞迴,不用堆疊的方法,一個決定移動最大或者是最小的計數器,然後一直迭代即可。」-和教授 2012/10/18

#include <stdio.h>
#define N 1048576
int ni[N], ac[N];
int main() {
    int n, i, j, k;
    while(scanf("%d", &n) == 1) {
        ni[0] = 1, ac[0] = 1;
        int len = 1;
        int g[6] = {1,0,4,5,2,3};
        int v[6] = {3,2,5,4,0,1};
        for(i = 2; i <= n; i++) {
            ni[len] = i, ac[len] = 1;
            for(j = 0; j < len; j++)
                ni[j+len+1] = ni[j], ac[j] = g[ac[j]];
            len = len*2+1;
            for(k = 0, j++; j < len; j++, k++)
                ac[j] = v[ac[k]];
        }
        for(i = 0; i < len; i++) {
            int A, C;
            if(ac[i] == 0)  A = 0, C = 1;
            else if(ac[i] == 1) A = 0, C = 2;
            else if(ac[i] == 2) A = 1, C = 0;
            else if(ac[i] == 3) A = 1, C = 2;
            else if(ac[i] == 4) A = 2, C = 0;
            else if(ac[i] == 5) A = 2, C = 1;
            printf("Move %d from %c to %c\n", ni[i], A+'A', C+'A');
        }
    }
    return 0;
}




部落格專用相簿


[資料結構] 誰說非遞迴河內塔不好寫的 ?



#include <stdio.h>
#include <stack>
using namespace std;

int main() {
    int n;
    int i, j, k;
    while(scanf("%d", &n) == 1) {
        stack<int> stk[3];
        for(i = n; i >= 1; i--)
            stk[0].push(i);
        char peg[] = {'A','B','C'};
        if(n&1)    swap(peg[1], peg[2]);
        while(true) {
            int disk[3];
            for(i = 0; i < 3; i++)
                disk[i] = stk[i].size() ? stk[i].top() : 0xfffffff;
            int mnIdx = 0;
            for(i = 1; i < 3; i++)
                if(disk[i] < disk[mnIdx])
                    mnIdx = i;
            printf("Move disk %d from %c to %c\n", disk[mnIdx], peg[mnIdx], peg[(mnIdx+1)%3]);
            stk[mnIdx].pop();
            stk[(mnIdx+1)%3].push(disk[mnIdx]);
            if(stk[1].size() == n || stk[2].size() == n)
                break;
            for(i = 0; i < 3; i++)
                disk[i] = stk[i].size() ? stk[i].top() : 0xfffffff;
            if(disk[0] > min(disk[1], disk[2]) && disk[0] < max(disk[1], disk[2])) {
                if(disk[1] < disk[2]) {               
                    printf("Move disk %d from %c to %c\n", disk[0], peg[0], peg[2]);
                    stk[0].pop(), stk[2].push(disk[0]);
                } else {
                    printf("Move disk %d from %c to %c\n", disk[0], peg[0], peg[1]);
                    stk[0].pop(), stk[1].push(disk[0]);
                }
            } else if(disk[1] > min(disk[0], disk[2]) && disk[1] < max(disk[0], disk[2])) {
                if(disk[0] < disk[2]) {
                    printf("Move disk %d from %c to %c\n", disk[1], peg[1], peg[2]);
                    stk[1].pop(), stk[2].push(disk[1]);
                } else {
                    printf("Move disk %d from %c to %c\n", disk[1], peg[1], peg[0]);
                    stk[1].pop(), stk[0].push(disk[1]);
                }
            } else {
                if(disk[0] < disk[1]) {
                    printf("Move disk %d from %c to %c\n", disk[2], peg[2], peg[1]);
                    stk[2].pop(), stk[1].push(disk[2]);
                } else {
                    printf("Move disk %d from %c to %c\n", disk[2], peg[2], peg[0]);
                    stk[2].pop(), stk[0].push(disk[2]);
                }
            }
        }
    }
    return 0;
}


台長: Morris
人氣(71,071) | 回應(2)| 推薦 (4)| 收藏 (0)| 轉寄
全站分類: 教育學習(進修、留學、學術研究、教育概況) | 個人分類: 其他題目 |
此分類下一篇:[練習] 打出垃圾碼,以 BrainFuck 為例
此分類上一篇:[C++][線性代數] 求行列式值

(悄悄話)
2013-05-03 08:07:01
(悄悄話)
2013-05-05 13:58:46
是 (若未登入"個人新聞台帳號"則看不到回覆唷!)
* 請輸入識別碼:
請輸入圖片中算式的結果(可能為0) 
(有*為必填)
TOP
詳全文