汉诺塔问题:汉诺塔问题源自印度一个古老的神话,印度教的“创造之神”梵蒂冈创造世界时做了3根金刚石柱,其中的一根柱子按照从小到大的顺序放着64个黄金圆盘。梵天命令一个叫婆罗门的门徒将所有的圆盘移动到另一个柱子上,移动过程中必须遵守以下规则:
每次只能移动柱子最顶端的一个圆盘
每个柱子上,小圆盘永远要位于大圆盘之上

核心代码
/** project : 汉诺塔* language:C* time:2023年1月25日* environment: VS2022*/#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <stdlib.h>/**全局标量* N:叠加的层数* sum:记录移动次数 2^n -1;**/int N;int sum;void move(char from, char to){printf("%c---->%c\n", from, to);sum++;}/** 汉诺塔递归算法* from 开始地* temp 中转地* to 移动目的地*/void hanoi(int n, char from, char temp, char to){if (1 == n){move(from, to);//递归截至条件}else{hanoi(n - 1, from, to, temp);move(from, to);hanoi(n - 1, temp, from, to);}}int main(void){printf("需要叠的层数:");scanf("%d", &N);hanoi(N, 'A', 'B', 'C');printf("移动总次数:%d", sum);return 0;}
汉诺塔CMD可视化
/** project : 汉诺塔CMD可视化* language:C* time:2023年1月25日* environment: VS2022*/#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <windows.h>/**定义地图相关信息* @sleepTime:等待时间* @autoPlay:是否自动播放* @wall:墙* @pillar:柱子* @hanoiLeft:汉诺塔圆盘左边显示* @hanoiRight:汉诺塔圆盘右边显示* @hanoiAir:汉诺塔圆盘中间镂空部分显示*/const int sleepTime = 5; //每隔多长时间移动一下const int autoPlay = 1; //是否自动进行 0手动播放,const char wall = '@';const char pillar = '^';const char hanoiLeft = '{';const char hanoiRight = '}';const char hanoiAir = '-';const int up = 0, down = 1, left = 2, right = 3;/*[控制移动]*@next_go 下一次移动方向 上0,下1左2右3*/int next_go[4][2] = { {0,-1},{0,1},{-1,0},{1,0} };/*系统变量*@abc_pillar[3][1000] 当前柱子放置的圆盘数* [高度,1长度,2长度,]* [i][0]存放第i个柱子当前高度* [i][j]表示第i个柱子第j层存放的圆盘大小* @abc_x[3] abc柱子的坐标* 数组可以直接通过ABC-'A'直接获取下标取值*全局标量* N:叠加的层数* sum:记录移动次数 2^n -1;*/int N;int sum;int abc_pillar[3][1000] = { {0},{0},{0} };int abc_x[3] = { 0,0,0 };int mapHeight, mapWidth;int deep;void gotoxy(int x, int y)//设置光标位置,从哪里开始输出{COORD pos;//表示一个字符在控制台屏幕上的坐标,左上角(0,0)pos.X = x;pos.Y = y;HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);//GetStdhandle用于从一个特定的标准设备(标准输入、标准输出或标准错误)中取得一个句柄(用来标识不同设备的数值)。可以嵌套使用。SetConsoleCursorPosition(handle, pos);}/**清空x,y地方的绘制* 并且绘制下一处长度为n的汉诺塔*/void drawHanoi(int& x, int& y, int n, int next) {// 清空原来的char* replace = (char*)malloc(sizeof(char) * (2 * n + 1));for (int i = 0; i < 2 * n + 1; i++) {replace[i] = ' ';if (i == n && y != 1) {replace[i] = pillar;}if (i == 2 * n) {replace[i + 1] = '\0';}}gotoxy(x - n, y);printf("%s", replace);// 绘制新的if (next != -1) {x += next_go[next][0];y += next_go[next][1];}for (int i = 0; i < 2 * n + 1; i++) {if (i == n && y != 1) {replace[i] = pillar;}else if (i == 0) {replace[i] = hanoiLeft;}else if (i == 2 * n) {replace[i] = hanoiRight;}else {replace[i] = hanoiAir;}if (i == 2 * n) {replace[i + 1] = '\0';}}gotoxy(x - n, y);printf("%s", replace);Sleep(sleepTime);}//定义隐藏光标函数void HideCursor(){CONSOLE_CURSOR_INFO cursor; //定义游标信息cursor.bVisible = FALSE; //设置游标不可见cursor.dwSize = sizeof(cursor); //设置游标不可见的数值HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorInfo(handle, &cursor); //定义光标的位置}void move(char from, char to){gotoxy(0, mapHeight);printf("\n\t%c--->%c\n", from, to);sum++;printf("\n\t移动次数:%d", sum);//获取from的柱子有多少高定位从哪开始int fromHeight = abc_pillar[from - 'A'][0]; //获取from柱子放的圆盘数int n = abc_pillar[from - 'A'][fromHeight];//获取顶部圆盘大小int x = abc_x[from - 'A'];//获取当前柱子的x坐标int y = 2 + N - fromHeight; //获取当前y坐标abc_pillar[from - 'A'][0]--;//将出发的柱子相减//获取to的柱子高度,定位到那结束abc_pillar[to - 'A'][0]++; //将到达位置+1int toHeight = abc_pillar[to - 'A'][0]; //获取to柱子的圆盘数abc_pillar[to - 'A'][toHeight] = n;//将顶部的圆盘存进去int to_X = abc_x[to - 'A']; //达到x的坐标int to_Y = 2 + N - toHeight; //到达y的坐标//取出盘--->上升到顶部while (y > 1){drawHanoi(x, y, n, up); //移动绘画出来}//移动盘,移动到指定位置if (x < to_X){while (x < to_X){drawHanoi(x, y, n, right);}}else if (x > to_X){while (x > to_X){drawHanoi(x, y, n, left);}}//放置盘---->下降到上面while (y < to_Y){drawHanoi(x, y, n, down);}//手动播放if (0 == autoPlay ){gotoxy(0, mapHeight + 2);printf("回车进行下一步");getchar();}}void init() {// 初始化柱子信息abc_pillar[0][0] = N;for (int i = 1; i <= N; i++) {abc_pillar[0][i] = N + 1 - i;}//高度 = 上下墙(2) + deep(4) + 上空行(1)//宽度 = 左右墙(2) + 3个区块[3*(deep*2+1)] + 两个中间空行(2)mapHeight = 2 + N + 1;mapWidth = 2 + 3 * (N * 2 + 1) + 2;//柱子0(a)水平坐标 = 左边墙(1) + deep(4)//柱子1(b)水平坐标 = 柱子1 + 2*deep + 2//柱子2(c)水平坐标 = 柱子2 + 2*deep + 2abc_x[0] = 1 + N;abc_x[1] = abc_x[0] + 2 * N + 2;abc_x[2] = abc_x[1] + 2 * N + 2;// 绘制地图for (int i = 0; i < mapHeight; i++) {for (int j = 0; j < mapWidth; j++) {//墙体绘制if (i == 0 || i == mapHeight - 1 || j == 0 || j == mapWidth - 1) {gotoxy(j, i);printf("%c", wall);}//绘制柱子else if (i > 1 && i < mapHeight - 1) {if (j == abc_x[0] || j == abc_x[1] || j == abc_x[2]) {//初始化绘制圆盘int abc_x_index = 0;if (j == abc_x[0]) abc_x_index = 0;else if (j == abc_x[1]) abc_x_index = 1;else if (j == abc_x[2]) abc_x_index = 2;drawHanoi(j, i, abc_pillar[abc_x_index][N - i + 2], -1);}}}}}/** 汉诺塔递归算法* from 开始地* temp 中转地* to 移动目的地*/void hanoi(int n, char from, char temp, char to){if (1 == n){move(from, to);//递归截至条件}else{hanoi(n - 1, from, to, temp);move(from, to);hanoi(n - 1, temp, from, to);}}int main(void){HideCursor();printf("需要叠的层数:");scanf("%d", &N);init();getchar();//读取换行HideCursor();hanoi(N, 'A', 'B', 'C');getchar(); //让暂时不退出getchar();return 0;}
参考资料:https://www.yuque.com/404name/works/onsok6
文章转载自瓶子的跋涉,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




