2019.9.26
阿萧上了C语言课并表示晕递归
我觉得一定要表现一波,加之之前看书也囫囵吞枣,还是做点题加深理解吧,毕竟递归比十连for(草)漂亮多了
汉诺塔问题(只求步数)
公式分析
1阶(1) 1-C
2阶(3) 1-B 2-C 1-C
3阶(7) 1-C 2-B 1-B 3-C 1-A 2-C 1-C
4阶时(15),可通过一定步骤简化为3阶,即4在C上,而123依次排列在B上
步骤如下 1-B 2-C 1-C 3-B 1-A 2-B 1-B 4-C
即先将123整体移动到B柱上
综上 4阶的解决方式为 将123整体移动到B柱 再将123整体移动到C柱
以此类推 5阶时为 将1234 整体移动到B柱 再将1234 整体移动到C柱
……
n阶时的步数:
(n-1)阶的步数*2+1,n>1;
1,n=1;
代码实现:
#include<stdio.h>
int hanoi(int i)
{
return i==1?1:hanoi(i-1)*2+1; //函数的返回值又用来调用函数
}
int main()
{
int i;
scanf("%d",&i);
printf("%d",hanoi(i));
return 0;
}
i 稍微大一点就爆int了,所以这里只用作理解有返回值的函数递归
题意:
总共十个1-3范围内的加数,要求加出指定的和,并输出不同组合的种数,及组合的具体内容
首先看输出:
如果是先输出具体组合再输出种数的话,只要一个一维数组,记录、输出数组、ans计数、再清空数组继续尝试就行了。
但这里要求是相反的,所以需要把组合的具体内容都存起来,故用到二维数组
然后是具体操作:
很容易想到
for(int i=1,i<=3,i++)
这样的十连for,但是太难看了,递归走起
#include<stdio.h>
int n,kind=0,method[10000][10],methoding[10];
//n为要求的美味程度,method储存方案,methoding储存正在尝试的方案
void tiaoliao(int a,int num){ //a为当前美味程度 num为已加入的调料种数
if(num==10){ //若十种调料已全部添加
if(a==n){ //若当前方案的美味程度符合要求
for(int j=0;j<10;j++){
method[kind][j]=methoding[j]; //将一个一维数组存入一个二维数组的一行中
}
kind++;
}
}
else if(a>=n) ;//若调料未加完,美味程度就已经达到或超出要求,不执行任何操作
else{ //若调料未加完,美味程度也没达到要求
for(int i=1;i<=3;i++){
methoding[num]=i;
tiaoliao(a+i,num+1);
}
}
}
int main(){
scanf("%d",&n);
tiaoliao(0,0);//初始美味程度为0,第一种调料的数组下标为0
//输出
printf("%d",kind);
for(int k=0;k<kind;k++){
printf("\n");//输出完一种方案就换行
for(int y=0;y<10;y++)
printf("%d ",method[k][y]);
}
return 0;
}
详解一下递归过程:
第一次调用丢了(0,0)进去,即初始美味程度为0,从第0种调料(注意数组下标的特殊性)开始。
递归开始,直到十种调料都加入。显然每一次递归都是在尝试下一种调料,所以要写 num+1 。同时要注意当前美味程度的累加,用累加值开始下一次递归,所以是 a+i 。
递归全过程的实质是把十种调料中的每一种的1-3的数值都尝试一遍。当然,n∈[10,30]的时候才会这样,其他都无解。
总结:
1.void类型函数的递归,其实还是用来得出某个或某些值的,如果没有这个值,那就得是执行printf之类的操作。本题中函数递归用来算kind和二维数组method。但函数返回值只能有一个,tiaoliao函数又要两个值,只能是void并且要在参数列表里搞点小操作。
2.要用自定义函数又想避开指针,就得用到全局变量,把主函数与自定义函数都可以修改的东西在最前面声明。注意不要重复声明,之前就是在main函数里又声明了一个n,导致其在tiaoliao函数中无法使用,最后调试了几分钟才发现。
3.代码其实是照着题解边理解边写的……
9.28 新的一天从A题开始
题意:
反复判断是否为回文,若不是则输出字符串长度
注意输出要求。一开始想到要对字符串反复处理修改其真实长度,但完全不需要,只要把数值直接砍一半就好
#include<stdio.h>
#include<string.h>
char necklace[100005];
int length;
void solve(char a[100005])
{
int flag=1;
if(length%2==0){ //判断是否偶数
for(int i=0;i<length/2;i++){
//判断是否回文 (千万注意这个是判断不了奇数字符串的!!)
if(necklace[i]!=necklace[length-i-1]) {flag=0;break;}
}
if(flag){
length/=2;//如果是回文 长度减半 继续判断
solve(necklace);
}
}
}
int main()
{
scanf("%s",necklace);
length=strlen(necklace);
solve(necklace);
printf("%d",length);
return 0;
}