比较高频的几个递归问题

1.递归求阶乘

int fun(int n)
{
	if (n == 1)
		return 1;
	else
		return n * fun(n - 1);
}

2.将所输入的5个字符按相反顺序输出

int convert1(int n)
{
	char ch;
	if (n == 1)
	{
		ch = getchar();
		putchar(ch);
	}
	else
	{
		ch = getchar();//相当于每次读取一个字符放进假想的一个栈中
		convert1(n - 1);
		putchar(ch);//逐个出栈
	}
	return 0;
}

3.逆序输出一个整数

int convert(char a[], int c)
{
	int i;
	if ((i=c / 10) != 0)
	{
		convert(a + 1, i);//第一次回溯时将最高位放在最后一位
	}
	*a = c % 10 + '0';
	return 0;
}

4.枚举排列组合

给定集合S={a,b,c,d,e,f},求其任意三元素构成的集合

#include<stdio.h>
enum yuansu//定义一个名叫enum yuansu的枚举类型,有点类似于结构型定义,此后a在其他地方就被当做0了,当然还有17行的特殊情况
{
	a, b, c, d, e, f, g
};
int main()
{
	//enum yuansu {a,b,c,d,e,f,g} p;另一种定义枚举类型的方法,c语言规定,此时将视为这个枚举类型里的元素为整数,此时外部函数无法调用
	//a=0,b=1......以此类推
	yuansu i=a, j=b, k=c;//定义了三个枚举类型的元素(类比于int a,b,c)
	void pailie(int,int,int);
	pailie(i, j, k);
	return 0;
}
void pailie(int i,int j,int k)
{
	//int a = 15;//还需注意:此处变量a与枚举元素中的a名字重复了,在下面的程序中,系统将会优先将a当做整型变量a而非0
	int sum = 0, loop = 0,loop1;
	for (i = a; i <= g; i++)
	{
		for (j = a; j <= g; j++)
		{
			if (i != j)
			{
				for (k = a; k <= g; k++)
				{
					if (k != i && k != j)
					{
						sum++;
						printf("第%d种组合方式为:", sum);
						for (loop = 0; loop < 3; loop++)
						{
							switch (loop)
							{
							case 0:loop1 = i;
								break;
							case 1:loop1 = j;
								break;
							case 2:loop1 = k;
								break;
							default:
								break;
							}
							switch (loop1)
							{
							case 0:
								printf("a ");
								break;
							case 1:
								printf("b ");
								break;
							case 2:
								printf("c ");
								break;
							case 3:
								printf("d ");
									break;
							case 4:
								printf("e ");
								break;
							case 5:
								printf("f ");
								break;
							case 6:
								printf("g ");
								break;
							default:
								break;
							}
						}
						putchar('\n');
						
					}
				}
			}
		}
	}
}
//针对29~69行代码,最初我想用
//printf("第%d种组合方式为:%d %d %d\n", sum,(enum yuansu)i,(enum yuansu)j,(enum yuansu)k);
//所代替,我以为此时可以将整型变量在转换成枚举类型,然后输出对应的枚举元素,事实证明并不能如此,c语言将枚举类型里面
//的枚举元素完全当做一个个整型变量了,你就算用了强制转换他也依然是整型

5.从n个数中抽r个数的组合方式

组合:不要求顺序,选出来即可,是C
排列:要求顺序,同种元素排列不同结果也不同,是A
全排列:就是A上下标相等的情况

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int *a = NULL, an;
	int *b = NULL, bn;
	int R, sum = 0;
	printf("请输入a数组的元素个数:\n");
	scanf("%d", &an);
	a = (int *)malloc(sizeof(int)*an);
	printf("请为这%d个数依次赋值\n", an);
	for (int i = 0; i < an; i++)
	{
		scanf("%d", &a[i]);
	}
	printf("你打算每次从这%d个数中取几个数?\n", an);
	scanf("%d", &bn);
	b = (int *)malloc(sizeof(int)*bn);
	R = bn;
	int combine(int, int, int, int*, int *,int &);
	sum=combine(an, bn, R, a, b,sum);
	printf("共计%d个\n", sum);
	return 0;
}
int combine(int an, int bn, int R, int *a, int *b,int &sum)
{
	if (bn == 0)
	{
		for (int i = 0; i < R; i++)//设置一个R的目的是bn一直在参与递归,时刻在变,用R来保存抽取的个数
		{
			printf("%d", a[b[i]]);//b[i]中存放某个组合数在a数组中的下标
		}
		sum++;
		printf("\n");
	}
	else
	{
		for (int j = an; j >= bn; j--)//记下这组循环条件,它指明了选取每个组合数时会有几种情况(本题中每趟循环三次,证明每个组合数有3种情况),以后类似题可以类比此条件
		{
			b[bn - 1] = j - 1;//别写成b[bn-1]=an-1
			combine(j - 1, bn - 1, R, a, b,sum);//别写成combine(an-1,bn-1,R,a,b,sum)
		}
	}
	return sum;
}
/*
由于组合是无顺序的,所以我们可以采取从特殊到一般的方法去想,假设a数组为{1,2,3,4,5},我们
选取的结果的数字是从大到小的,那么对于第一个数我们可以在3,4,5中选一个,第二个数在比
第一个选出的那个数小的集合中选取,以此类推直到三个数选好我们就可以输出,接着递归回溯又可以
改变最后一个被选出数的其他情况,逐层回溯,最终输出所有情况

*/

6.求几个数的全排列

求几个数的全排列

7.递归求具有n个元素的整型数组的和

算法思想:n个元素的和等于前n-1个元素的和+第n个元素,依次类推

int sum(int R[], int n)
{
	if (n == 1)
		return R[0];
	else
		return (R[n - 1] + sum(R, n - 1));
}

8.递归求具有n个元素的整型数组R的平均值

int average(int R[], int n)
{
	if (n == 1)
		return R[0];
	else
		return (R[n - 1] + average(R,n-1)*n-1)/n;
}

//算法思想:5个数的平均值等于第(第五个数+前四个数)/5,其中前4个数需写成平均值在乘以个数的形式——average(R,n-1)*n-1

9.分鱼问题

#include<stdio.h>
int main()
{
	int fun(int , int );
	int i = 6, flag = 0;//想要满足扔掉一条鱼且可给5人均分的情况下的最小值就为6,此后每次+5同样满足
	do
	{
		if (fun(1, i))
		{
			flag = 1;
			printf("一共%d条\n", i);
		}
		i += 5;
	} while (!flag);
	return 1;
}
int fun(int n, int x)//第n个人分鱼前有x条鱼
{
	if ((x-1)%5 == 0)//保证每个人分鱼前数量符合要求
	{
		if (n == 5)//如果n==5了,就证明一开始选的x很合适
			return 1;
		else
			return fun(n+1, (x-1)*4/5);//下一个人分鱼前鱼的数量为(x-1)*4/5
	}
	return 0;
}

10.子孙数

#include<stdio.h>
int main()
{
	int n = 0;
	printf("请输入一个数:\n");
	scanf("%d", &n);
	int fun(int);
	printf("此数的子孙数有%d个\n",fun(n));
	return 0;
}
int best(int n)
{
	while (n / 10 != 0)
	{
		n = n / 10;
	}
	return n;
}

int fun(int n)
{
	int best(int);//best用于求某个数的最高位是几
    static	int sum = 0;//防止下一次进入递归在对sum初始化
	int i;
	if (best(n) == 1)
	{
		sum++;
	}
	else
	{
		sum++;//即使最高位不是1,但是它本身也应该算作一个子孙数
		for (i = 1; i <= best(n) / 2; i++)
		{
			fun(i);
		}
	}
	return sum;
}

11.求具有n个元素的数组的最大值

#include<stdio.h>
int main()
{
	int a[10];
	for (int i = 0; i < 10; i++)
		scanf("%d", &a[i]);
	int fun(int[], int);
	printf("%d\n", fun(a, 10));
	return 0;
}
int fun(int a[], int n)
{
	if (n == 1)
		return a[n - 1];
	else
		return a[n - 1] > fun(a, n - 1) ? a[n - 1] : fun(a, n - 1);
}

12.猴子吃桃问题

#include<stdio.h>
int main()
{
	int fun(int);
	printf("%d\n", fun(1));//因为问题总量是10天,而不要忘记当n==1的此时的状态也在栈中,所以当n==10时刚好栈中存了10个状态
	//若n从0开始,则存储11个状态,最终结果翻了一倍
}
int fun(int n)
{
	if (n == 10)//注意循环次数的设置
		return 1;
	else
	{
		return 2 * (fun(++n) + 1);
	}
}
/*
重要算法思想:递归本质是栈,而对于递归问题,我们总是将以目前条件不能解决的问题依次入栈,直到出现可以解决的条件了然后依次出栈解决
各个遗留的问题,这个过程也叫回溯,所以在本道题中,由于刚开始桃子数我们不知道,所以我们假想将第一天的情况入栈,依次类推
直到将第10天的情况入栈后,发现当前栈顶元素有能力解决它下面遗留的那些问题,于是他先出栈然后依次解决栈中的问题直至栈空(返回主函数)
所以说在本道题中相当于某状态下的问题需要它后面状态的结果才可以解决,因此我们将这些尚未解决的问题入栈,直到出现可以解决问题
的结果了在出栈所表达的正是栈“先进后出”的特性,其中“后出”也就是回溯,也就是真正每个问题得到答案的时候
*/

13.猴子吃桃问题

#include<stdio.h>
int main()
{
	int i = 2, sum = 1;
	do
	{
		sum = (sum + 1) * 2;
		i++;
	} while (i <= 10);
	printf("%d\n", sum);
}
/*
将此题设为重点不是在于问题本身多难,而是注意循环变量i的初始值设为多少才合适,我们将sum = (sum + 1) * 2;这一句理解为
当前i下的桃子总数,比如刚开始i为2,就理解为倒数第二天的桃子数,为4,显然是正确的,若i初始值为1,则证明倒数第一天桃子数为
4,显然与题干不符。
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值