zoukankan      html  css  js  c++  java
  • 分治算法一:汉诺塔

    一、分治算法与递归

    (1)分治算法,是指将一个规模较大的问题分解成多个小规模的子问题进行处理;当问题规模足够小时,处理策略就相当简单明了了;
    (2)若这些子问题有相似的处理方法,则可以使用递归结构处理;
    (3)递归-三步走
    递归出口:通常是问题规模最小时,最简处理策略;
    递归过程:将大规模问题,逐步拆解成小问题的过程,递归的精髓皆在于此;
    本层递归处理:各问题处理过程的衔接,还未理解透彻,处理比较麻烦。
    (4)分治策略:
    分解:将问题分解成若干个子问题;
    治理:递归解决各子问题;
    合并:将子问题的解合并成原问题的一个解。

    二、汉诺塔问题

    (1)问题说明:有三根柱子A、B、C,A柱上有n个大小不同的圆盘,大盘在下,小盘在上;需要将A柱上的盘子移动到C柱上,同样保持大盘在下小盘在上,移动过程中不允许大盘叠放在小盘上。
    (2)分析:当仅A柱上仅有一个圆盘时,直接将其放到C柱上即可——最小规模问题,递归出口
    若A上有n(n>1)个圆盘,则将其前n-1个圆盘移动到过渡柱B上,然后将其转化成最小规模问题处理——分解策略,递归过程
    (3)因为盘子最后都要放到一个柱子上,且大盘在下小盘在上(默认没有相同大小的盘子),所以各个盘子都是唯一的

    三、代码实现

    // 查找x柱子上最底下一个圆盘的下标(当前x柱子上仅剩下一个圆盘,所以在current数组中有唯一下标)
    int pickTopDisk(char *current, char x)
    {
        int i = 0;
        while (current[i] != x) {
            i++;
        }
        return i;
    }
    
    /*
     * Description:三根木柱,将一根木柱上的圆盘借助中间木柱移动到另外一根木柱上,大圆盘不能放在小圆盘上
     * input: 各圆盘的位置数组current,圆盘数量num,圆柱位置标识A、B、C
     *        current的下标可以理解为各盘子的标记,下标越大盘子越大
     *        current的内容表示当前该盘子放置的位置,A-源柱子,B-过渡柱子,C-目标柱子
     * output: 动态输出圆盘移动步骤
     */
    static int hanoiTower(char *current, int num, char A, char B, char C)
    {
        // count表示移动次数
        static int count = 0;
        int i = 0;
        // 递归出口:当只有一个盘子时,直接将其移动到目标盘
        // 仅有一个盘子时,此时盘子应在A柱子上(单个递归过程),需要明确该盘子的大小,即在current中的下标,将该下标对应内容改成C柱即可
        if (num == 1) {
            // 当前current中,仅有一个A,获取其下标
            i = pickTopDisk(current, A);
            // 模拟从A柱移动到C柱的操作,并增加操作次数
            current[i] = C;
            count++;
            printf("move %d disk %d: %c -> %c 
    ", count, i + 1, A, C);
            return 0;
        }
        // 递归过程:当当前需要移动的盘子不只一个时,需要先将A柱的n-1个盘子移动到B盘(此时,A依旧是源柱,B成为目标柱,C为过渡柱)
        hanoiTower(current, num - 1, A, C, B);
        // 本层递归处理:通过上一步骤的处理后,A柱上只剩下最大一个盘,下标为n-1,将其移动到C上
        current[num - 1] = C;
        count++;
        printf("move %d disk %d: %c -> %c 
    ", count, num, A, C);
        // 此时,B上有很多A之前的盘子,A空了,C上有一个A之前最大的盘子
        // 下面将B作为源柱,A作为过渡,C依旧为目标柱,且需要移动的盘子数量减一(因为已经将最大的盘子移动到C柱了)
        hanoiTower(current, num - 1, B, A, C);
        return 0;
    }
    

    四、测试结果

    测试代码:

    #include <stdio.h>
    
    #define DISK_NUM 4
    
    // hanoiTower()函数实现
    
    int main(void)
    {
        char current[DISK_NUM] = {'A', 'A', 'A', 'A'};
        char A = 'A';
        char B = 'B';
        char C = 'C';
        hanoiTower(current, DISK_NUM, A, B, C);
        while (1);
        return 0;
    }
    

    测试结果:

  • 相关阅读:
    字的传送
    mov 寄存器,段寄存器
    c语言中利用三维数组计算成绩总分数
    python中break语句
    c语言中求课程总分、平均分。学生总分及平均分
    python中assert语句
    python中random模块引入随机数
    python中实现列表的倒序排列
    c语言中求两个矩阵的乘积
    python的严格缩进可以避免else悬挂
  • 原文地址:https://www.cnblogs.com/HZL2017/p/14320961.html
Copyright © 2011-2022 走看看