ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

n阶汉诺塔问题

2021-03-26 23:02:01  阅读:292  来源: 互联网

标签:count int id 问题 汉诺塔 TowerOfHanoi disk order


问题描述

        在汉诺塔(Towers of Hanoi)问题中,假设有n个碟子和3座塔。初始时所有碟子从大到小堆在塔x上,我们要把所有碟子都移动到塔z上,每次移动一个,而且任何时候都不能把大碟子压在小碟子的上面。

求解策略

        递归。
        为了把最大的碟子移到塔3的底部,必须把其余n-1个碟子移动到塔2,然后把最大的碟子移动到塔3。接下来是把塔2上的n-1个碟子移动到塔c。为此可以利用塔1和塔3。可以完全忽略塔3上的已有的一个碟子,因为我们已经把最大的碟子移到塔3,在它顶上可以堆放任何一个碟子。
        下面用n=3时来模拟求解过程。
        初始时:
在这里插入图片描述
        我们想把三个碟子都移动到塔3,首先要把上面两个碟子看成一个整体,移动到塔2:
在这里插入图片描述
        那么如何把上面两个碟子移动到塔3碟子的上面?首先要把塔2的第一个碟子移到塔1:
在这里插入图片描述
        这就是递归思想,下面一步一步的模拟过程,以下是递归算法:

void Move(int id, TowerOfHanoi *a, TowerOfHanoi *b) {
    //将编号为n的圆盘从塔盘a移至b
    int i;
    if (Find(id, a) == FALSE) {
        printf("编号为%d的圆盘不在塔盘上\n", id);
        return;
    }
    if (a->disk[0] != id) {
        printf("编号为%d的圆盘不在塔顶,无法操作\n", id);
        return;
    }
    for (i = 0; i < a->count - 1; i++) {
        //移动塔盘a上的圆盘
        a->disk[i] = a->disk[i + 1];
    }
    for (i = b->count - 1; i >= 0; i--) {
        //移动塔盘b上的圆盘
        b->disk[i + 1] = b->disk[i];
    }
    b->disk[0] = id;
    a->count--;
    b->count++;
    Step++;//每移动一步,步数加一
}

void Hanoi(int n, TowerOfHanoi *x, TowerOfHanoi *y, TowerOfHanoi *z, int order) {
    //将x塔座上编号为1到n的盘子移动到塔座z上,y为中转站
    if (n == 1) {
        Move(n, x, z);
        PrintHanoi(x, y, z, order);
    } else {
        Hanoi(n - 1, x, z, y, order);
        Move(n, x, z);
        PrintHanoi(x, y, z, order);
        Hanoi(n - 1, y, x, z, order);
    }
}

        第一步:
在这里插入图片描述
        第二步:
在这里插入图片描述
        第三步:
在这里插入图片描述
        第四步:
在这里插入图片描述
        第五步:
在这里插入图片描述
        第六步:
在这里插入图片描述
        第七步:
在这里插入图片描述
        下面是源代码,求解n阶汉诺塔问题(C语言实现):

递归过程中因为传参的问题让输出汉诺塔的时候塔的相对位置发生变化,结果没有问题

#include <stdio.h>
#include <stdlib.h>

#define TRUE 1
#define FALSE 0

typedef int ElementType;//表示元素类型
typedef int Status;//表示函数返回状态
typedef struct {
    int count;//表示圆盘数量
    int *disk;//圆盘数组,用 disk[0] 表示塔顶
} TowerOfHanoi;
int Step = 0;//记录步数

void CreatHanoi(TowerOfHanoi *x, TowerOfHanoi *y, TowerOfHanoi *z, int n);//初始化汉诺塔x,y,z,汉诺塔阶数为n
void Move(int id, TowerOfHanoi *a, TowerOfHanoi *b);//将编号为id的圆盘从塔盘a移至b
Status Find(int id, TowerOfHanoi *t);//检测编号为id的圆盘是否在塔盘t上
void Hanoi(int n, TowerOfHanoi *x, TowerOfHanoi *y, TowerOfHanoi *z, int order);//将x塔座上编号为1到n的盘子移动到塔座z上,y为中转站
void PrintHanoi(TowerOfHanoi *x, TowerOfHanoi *y, TowerOfHanoi *z, int order);//输出汉诺塔

int main() {
    ElementType order;//存放汉诺塔阶数
    scanf("%d", &order);
    TowerOfHanoi x, y, z;
    CreatHanoi(&x, &y, &z, order);
    PrintHanoi(&x, &y, &z, order);
    Hanoi(order, &x, &y, &z, order);
    return 0;
}

void CreatHanoi(TowerOfHanoi *x, TowerOfHanoi *y, TowerOfHanoi *z, int n) {
    //初始化汉诺塔,将盘子堆到x塔盘上
    int i;
    x->count = n;
    y->count = z->count = 0;
    //为塔盘分配空间
    x->disk = (ElementType *) malloc(sizeof(int) * n);
    y->disk = (ElementType *) malloc(sizeof(int) * n);
    z->disk = (ElementType *) malloc(sizeof(int) * n);
    for (i = 0; i < n; i++) {
        x->disk[i] = i + 1;
        y->disk[i] = 0;
        z->disk[i] = 0;
    }
}

Status Find(int id, TowerOfHanoi *t) {
    //检测编号为id的圆盘是否在塔盘t上
    int i;
    for (i = 0; i < t->count; i++) {
        if (t->disk[i] == id)
            return TRUE;
    }
    return FALSE;
}

void Move(int id, TowerOfHanoi *a, TowerOfHanoi *b) {
    //将编号为n的圆盘从塔盘a移至b
    int i;
    if (Find(id, a) == FALSE) {
        printf("编号为%d的圆盘不在塔盘上\n", id);
        return;
    }
    if (a->disk[0] != id) {
        printf("编号为%d的圆盘不在塔顶,无法操作\n", id);
        return;
    }
    for (i = 0; i < a->count - 1; i++) {
        //移动塔盘a上的圆盘
        a->disk[i] = a->disk[i + 1];
    }
    for (i = b->count - 1; i >= 0; i--) {
        //移动塔盘b上的圆盘
        b->disk[i + 1] = b->disk[i];
    }
    b->disk[0] = id;
    a->count--;
    b->count++;
    Step++;//每移动一步,步数加一
}

void Hanoi(int n, TowerOfHanoi *x, TowerOfHanoi *y, TowerOfHanoi *z, int order) {
    //将x塔座上编号为1到n的盘子移动到塔座z上,y为中转站
    if (n == 1) {
        Move(n, x, z);
        PrintHanoi(x, y, z, order);
    } else {
        Hanoi(n - 1, x, z, y, order);
        Move(n, x, z);
        PrintHanoi(x, y, z, order);
        Hanoi(n - 1, y, x, z, order);
    }
}

void PrintHanoi(TowerOfHanoi *x, TowerOfHanoi *y, TowerOfHanoi *z, int order) {
    int i, j;
    printf("第%d步:\n", Step);
    for (i = 0; i < order; i++) {
        //控制行
        for (j = 0; j < order * 3 + 2; j++) {
            //控制列
            if (order - x->count <= i && x->disk[i - (order - x->count)] > j) {//输出x
                //判断能否打印并且打印的数量
                printf("=");
            } else {
                printf(" ");
            }
            if (order - y->count <= i && y->disk[i - (order - y->count)] >= j - order && j - order > 0) {//输出y
                //判断能否打印并且打印的数量
                printf("=");
            } else {
                printf(" ");
            }
            if (order - z->count <= i && z->disk[i - (order - z->count)] >= j - 2 * order && j - 2 * order > 0) {//输出z
                //判断能否打印并且打印的数量
                printf("=");
            } else {
                printf(" ");
            }
        }
        printf("\n");
    }
}


        输入n=3时,输出结果:
在这里插入图片描述

标签:count,int,id,问题,汉诺塔,TowerOfHanoi,disk,order
来源: https://blog.csdn.net/weixin_46237604/article/details/115256244

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有