递推专题组(经典例题)(特别详细的解读)(锻炼思维为主)(普通版)

          9b45fab8c2c8439293deff0d38fcd980.png

        本集为普通版,由于这个是在初学递推时所写,虽然多,思路还行,但是就是没有逻辑感,对递推还没到精髓的程度,所以作者会再出一集详细版,为读者整理好思路,然后更加有逻辑的去理解递推为何物,如何去理解递推这个思想!

           递推在c语言学习中是一个十分关键的思想,我们最初的递推可以源于数学的全排列,递推规律(数列)甚至脑筋急转弯(高考题中也有递推的数列题(emm,概率和统计那块(全国卷为例))),而这里整理了一些递推 经典题,目的是帮助我自己理清递推的思路,如有侵权,请联系我!!

经典例题1

题目描述

爬楼梯(简单版1)(入门)

欧老师爬楼梯,他可以每次走 11 级或者 33 级,输入楼梯的级数,求不同的走法数。

例如:楼梯一共有 3 级,他可以每次都走一级,或者一次走三级,一共 2 种方法。

输入格式

输入包含若干行,每行包含一个正整数 N,代表楼梯级数,1<=N<=30。

输出格式

不同的走法数,每一行输入对应一行输出。

样例1

输入

1
3
5

输出

1
2
4

很好,那么我们很快能while(scanf("%d",&a[i])!=EOF)来处理多组输入的数据,再用一个循环来输出,那么问题在于怎么去算出这个递推!!!

我们看到这道题其实难度比较难(较初学者来说,可以先去学一下跨1和2阶的),我们学习1和2阶的思路,我们找到F(n)=F(n-1)+F(n-3)的递推式(我们假设我们到了最后一步,那么我们可以跨1步或3步来结束爬楼梯),那么就可以仿照写出oy(int n)的函数,不过请注意,这里以 2为例,我们要考虑所有出口即为n==1或者n==3,那么4就是3和1,5是2和4,那这个2我们没定义呀,我们知道2是1种方法(2个1步),那么就可以写出下面的代码!!

//递推爬楼梯
#include<stdio.h>
int oy(int n)//重点在这个函数
{
	if(n==1||n==2)//浓缩了一下
		return 1;
	if(n==3)
		return 2;
	else 
		return oy(n-1)+oy(n-3);//我的建议是以特殊情况举例,比如4(3和1),5(4和2)那就出口必须有123
}
int main()
{
	int a[1000],i=0;
	while(scanf("%d",&a[i])!=EOF)
	{
		a[i]=oy(a[i]);
		i++;
	}
	for(int j=0;j<i;j++)
	{
		printf("%d\n",a[j]);
	}
	return 0;
}

 

例题2 全排列

题目描述

输入一个数 N, 求 1到 N 的全排列。

输入格式

输入一个 N,N<12。

输出格式

输出 N 的全排列,每个数字占 4 个位置。

样例1

输入

3

输出

   1   2   3
   1   3   2
   2   1   3
   2   3   1
   3   1   2
   3   2   1

那么这道题拿到手,我们初学者可能就直接写几个循环就敷衍了事,甚至有的人都不知道在说什么,我们先简单点,只用打出他的组数,那么我们按我们前面的例题思路(可以这么写)

#include<stdio.h>
int oy(int n)
{
	if(n==1)
		return 1;
	else if(n==2)
		return 2;
	else
		return n*oy(n-1);
}
int main()
{
	int a;
	scanf("%d",&a);
	printf("%d",oy(a));
	
}

但其实我们可以学习一个新的概念深度优先搜索(DFS),emm,不耍流氓先说概念:

深度优先搜索   

深度优先搜索 (Depth-First Search,DFS)是一种常见的图搜索算法,它可以用于遍历或搜索树或图的数据结构。深度优先搜索从根节点开始,沿着一条路径一直搜索下去,直到到达最深的节点或无法继续搜索为止,然后回溯到上一个节点,继续搜索其他路径,直到所有节点都被访问过为止。

emm,读者可以去对比广度优先搜索(BFS),这里赘述!!

深度优先搜索算法的步骤如下:

  1. 从起始节点开始搜索,将其标记为已访问。
  2. 沿着一条路径一直搜索下去,直到到达最深的节点或无法继续搜索为止。
  3. 回溯到上一个节点,继续搜索其他路径,直到所有节点都被访问过为止。

深度优先搜索算法的应用非常广泛,例如在迷宫问题、拓扑排序、连通性问题、最短路径问题等方面都有应用。

具体做法你可以看一下这篇博客:DFS入门讲解

所以腻,为了方便读者理解,我也写一下(较为通俗的代码)

#include<stdio.h>
int p[10000]={0},l[1000]={0};
int k;
void oy(int n)//如果把这个排列看成盒子,那n就是你走到第几个盒子了
{
	if(n==k+1)//走到第k+1个盒子则立马结束,
	{
		for(int i=1;i<=k;i++)
			printf("%d ",p[i]);//立马打印这一行
		printf("\n");
		return;//结束
	}
	for(int i=1;i<=k;i++)
	{
		if(l[i]==0)
		{
			p[n]=i;//将号码放到盒子里
			l[i]=1;//标记他被使用了
			oy(n+1);//走到下一个盒子,123或者132;然后走到最后一个盒子,return,之后1的排列结束,所有的数字变成都没被使用,继续2
			l[i]=0;
		}	
	}
	return;
}
int main()
{
	scanf("%d",&k);
	oy(1);
	return 0; 
	
}

例题三:成群的奶牛

题目描述

现有 n 只奶牛在一片宽广的草地上吃草,草地有一些小路,可以去到其他草场。这些小路都是单向的。

每个草场有 2 条小路可以去到到其他草场,但是只有 1条小路可以到达这个草场。

奶牛从其中一个草场开始,每遇到一个草场,奶牛们会精确地分成两群,这两群奶牛数量之差的绝对值为 k,分别从两条路去到下一个草场(如果数量不满足要求就不会再分裂)。

当来到一个草场而该奶牛群已不可再分割时,奶牛们就会停下来在这里吃草。

现给出 n 和 k,求奶牛最终会分成多少群。

输入格式

一行,分别是 n 和 k,用空格隔开。

输出格式

一个正整数,表示最终奶牛会分成多少群。

样例1

输入

50 4

输出

2

样例2

输入

49 1

输出

6

数据规模与约定

0<n≤10000

0<k<n

那么我们知道,递推嘛,肯定先找出口,这题我们可以举个例子,比如样例的k=4;我们 选用8为例子 (如下丑图)

df27788f526d40d8a92068e95d143988.jpeg

我们不难得出,每次分裂后的两个数为(n-k)/2和(n+k)/2,不满足的条件要么现在这个数比k小,要么分解后是分数(这个怎么去表示?(分数用相加不等于原数表示))

//成群的奶牛
#include<stdio.h>
int a,b;
int o=1;//o代表有几群奶牛
void oy(int n)
{
	int p=(n-b)/2;//格外注意这里的int不能提到函数外面,第一,这个是函数使用时产生的一个临时参数,放外面就变成了占内存的实际参数了
	int l=(n+b)/2;//先定义两个分裂数出来
	if(p+l!=n)
		return;//不返回值(定义需为void),用于跳出
	o++;//这里建议去画图体会一下o数量的变化
	if(p>b)
		oy(p);
	if(l>b)
		oy(l);
	
}
int main()
{

	scanf("%d %d",&a,&b);
	oy(a);
	printf("%d",o);
	return 0;
	
}

小小结

写到这里我们发现了例一中的return oy(n-1)+oy(n-3)起到了一个sum的作用,其实就是将其全部计算出来后相加,比如要oy(n-3)那就把那n-3递推,而在这个奶牛中我们定义了一个o计数器,emm,区别就在于1.我们不返回值,2.我们只要知道次数就行,本质就是他不满足f(n)=f(n-k)+f(n-j)类,而是一种条件类!!!!

例四:初级快速幂训练

题目描述

请你计算an次方是多少,由于答案可能会很大,所以你只需要输出答案和b取余数的结果。

输入格式

多组输入,EOF结束。

每组一行,输入三个非负整数分别表示 a,n,b,(a,b,n均在int范围内)。

输出格式

对于每一组输入,在新的一行输出结果。

样例1

输入

2 10 10
3 3 5

输出

4
2

看完前四例后我们提高一下 难度,体会一下递推的神奇之处,也给大家一种新的求幂的算法

//初级快速幂(分治或者递归思想)
#include<bits/stdc++.h>//c++的头文件
using namespace std;
long long oy(long long a, long long n, long long b)//二分法递归快速幂(其实就是分治算法,但是我喜欢称之为递推)
{//首先这是一个计算a的n次方的函数(记住哦)
	if (n <= 1)				//递归出口设置为当指数为1
							//当n被分解到1或者等于0(这里只考虑者两种情况)
	{						//0去分解答案为1
		if (n == 0)
			return 1 % b;
		else				//1答案为a的1次幂去%b
			return a % b;
	}						//理解这里的递推!!
	long long half = n / 2;					//二分法开始了(一半赋给half)
	long long  tem= oy(a, half, b);			//计算少一半次数的a的n/2次方==临时tem
	if (n % 2 == 0)							//对指数操作:
	{
		return (tem * tem) % b;				//能被2整除即可以用tem*tem求出所有
	}
	else
	{
		return (tem * oy(a, half + 1, b)) % b;//不能的话就是乘多一项(int会砍掉小数,自然得到的tem是小的那一个)
	}
}
int main()
{
	long long int a, n, b,i=0,o[100000];
	while (scanf("%lld %lld %lld", &a, &n, &b) != EOF)
	{
		o[i]=oy(a,n,b);
		i++;
	}
	for(int j=0;j<i;j++)
	{
		printf("%d\n",o[j]);
	}
	return 0;
}

例五:分型三角形 

题目描述

有一些少数民族的图腾是分形三角形,你能画出来吗?

输入格式

一个整数 n,表示图腾的大小。

输出格式

若干行,表示图腾的样子。

样例1

输入

3

输出

       /\
      /__\
     /\  /\
    /__\/__\
   /\      /\
  /__\    /__\
 /\  /\  /\  /\
/__\/__\/__\/__\

数据规模与约定

1≤n≤10

 

 

ps:补充爬楼梯的一道小习题

1.超级楼梯

题目描述

有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法?

输入格式

输入数据首先包含一个整数N,表示测试实例的个数,然后是N行数据,每行包含一个整数M(1<=M<=40),表示楼梯的级数。

输出格式

对于每个测试实例,请输出不同走法的数量

样例

输入

2
2
3

输出

1
2

 这题很简单我就不再赘述

//超级楼梯
#include<stdio.h>
int oy(int n)
{
	if(n==1)
		return 1;
	if(n==2)
		return 1;
	else
		return oy(n-1)+oy(n-2);//同理的思维,以3(2和1),4(3和2)得出出口必须有1或2
}
int main()
{
	int i,a,b[10000];
	scanf("%d",&a);
	for(i=0;i<a;i++)
	{
		scanf("%d",&b[i]);
		b[i]=oy(b[i]);
	}
	for(int j=0;j<i;j++)
	{
		printf("%d\n",b[j]);
	}
	return 0;
}

再写下去太长了,期待下次更新在和大家见面!

如果这个能帮助到未来的你,我不胜感激

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值