1)汉诺塔轨迹输出
有三根杆子A,B,C。A杆上有 N 个 (N>1) 穿孔圆盘,盘的尺寸由下到上依次变小。
要求按下列规则将所有圆盘移至 C 杆:
每次只能移动一个圆盘;
大盘不能叠在小盘上面。
利用递归的方式,打印出移动轨迹
解决:hio函数对应输出移动的步数,move用于打印出每一次的轨迹
- 本题拓展:当输入一个固定的数值,输出该数值对应的步骤移动路径,该如何输出?
- 解决:增加一个全局变量,用来在递归的时候计算步数,输入的数值m作为参数传入函数,那么对应的输出也要修改,主要是修改move函数。拓展题代码放在下面:
- 需要注意的就是,对于m做一个基本的判断 是否是步数范围只能 否则程序报错。
- 而其中具体步数的增加是在两个部分,一个是退出循环时,另一个就是if之外。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
# include<stdbool.h>
#include<stdlib.h>
# include<math.h>
int step;
void move(int n,int m, char start, char mid, char end) {
/*step表示输出具体的哪一步 m是用于判断当前步数是否是m+1 */
if (n == 1) {
// printf("%c->%c\n", start, end);
step++;
if (step == m) {
printf("第%d的移动轨迹是:%c->%c\n",m, start, end);
}
return;//出口
}
//正常分成三步,第一步(n-1)1-->3
move(n - 1,m, start, end, mid);
step++;
if (step == m) {
printf("第%d的移动轨迹是:%c->%c\n", m, start, end);
}
//第三步 中间移到 目标
move(n - 1,m, mid, start, end);
}
int hio(int n, int m) {
if (m > (1LL << n) - 1) {
printf("程序错误!!!步数超出范围!!");
exit(1);
}
printf("%d个盘子的汉诺塔问题,", n);
move(n, m, 'A', 'B', 'C');
return (1LL << n) - 1; //步数不需要每一步都实现,直接通过公式计算出当下的步数即可
}
int main() {
int num, num1,m;
scanf("%d%d", &num,&m);
printf("%d",hio(num,m));//返回步数
return 0;
}
2) 十进制转换成二进制
给定任意一个非负十进制整数,请利用递归的方式,求解它的二进制表示方式
基本的思路是:把该整数除以2得到余数,然后倒着输出余数。
思考一下:如何实现倒着打印余数呢?
解决:translate_对应解决十进制转换成二进制。倒着打印对应的是回溯后的代码运行逻辑,程序注释中有详细解释。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
# include<stdbool.h>
# include<math.h>
void move(int n, char start, char mid, char end) {
//打印每一步的过程,也就是在移动的时候都需要输出
//当剩最后一个就是移动完成
if (n == 1) {
//不需要再n--到这一步了 直接输出然后向上回溯即可
printf("%c->%c\n", start, end);
return;//出口
}
//正常分成三步,第一步(n-1)个从第1-->第3
move(n - 1, start, end, mid);
//第二步 没有移动成功的大盘移到第三
//move(n - 1, start, mid, end); 为什么这一步不用迭代呢 因为 我迭代的目的就是输出移动方向,
//中间这一步是可以直接输出的 不用再迭代下去,所以直接输出就行
//我的理解是上面 n-1个移动作为第一步 但是具体的一步 对应的是一个move
//有出口 并且完成步骤分层理解清楚,需要的数据拿到就可以
printf("%c->%c\n", start, end);
//第三步 中间移到 目标
move(n - 1, mid, start, end);
}
void translate_(int num) {
if (num == 1) {
printf("%d", num % 2);
return ;
}
translate_(num >> 1);
printf("%d", num % 2); //递归想要每一次递归的结果 反向输出 就需要把输出放在递归函数后面即可
//至于为什么,解释一下
/*首先函数的会先执行 46行之前的函数 也就是先判断是否要退出,再更新num值,拿着 新的num值不断向下,直到
* num满足退出的条件 也就是在最后一次进入到函数中 判断num是等于1,输出此时的1 再通过return
* 开始向上回溯 ,而 回溯之后执行的是上一层的num 也就是 1退回到 2 num=2的这一层 循环 输出
* 2%2的结果 从而实现回溯的输出
* 那么相同的 如果是在translate_前面输出就是在向下走的过程中 先输出%2的值,在向下递归,也就是正向输出模数。
*/
}
int hio(int n) {
move(n, 'A','B', 'C');
return (1LL << n) - 1; //步数不需要每一步都实现,直接通过公式计算出当下的步数即可
}
int main() {
int num, num1;
scanf("%d", &num);
printf("%d",hio(num));//返回步数
scanf("%d", &num1);
translate_(num1);
return 0;
}
回溯: