洛谷过程函数与递归总结

P1028 数的计算

1.题目详情 洛谷P1028

2.实现方法

  这题一开始是想用递归的方法解决,就是定义一个全局变量来计数,然后通过题中该自然数不能超过原数一半的条件来结束调用,但是该方法时间复杂度过大,会超时,代码如下:

#include<stdio.h>
int s=1;
void sum(int n){
	int i;
	s+=n/2;
	for(i=2;i<=n/2;i++){
		sum(i);
	}
}
int main(){
	int n;
	scanf("%d",&n);
	sum(n);
	printf("%d\n",s);
	return 0;	
}

  本题可以从另一个角度切入,由于本题是对输入的数用相同的方法进行处理而且n较小,可以考虑是否可以用数学的方法去寻找相邻项的递推关系,然后用循环跑一遍就可以解决,所以可以先枚举前几项来找找规律:

a[1]=1;
a[2]=2;a[3]=2;
a[4]=4;a[5]=4;
a[6]=6;a[7]=6;
a[8]=10;a[9]=10;

  可以发现a[2n]=a[2n+1],而隔项看可以找到递推的规律:

a[1]=1;
a[2]=a[1]+1;
a[3]=a[1]+1;
a[4]=a[1]+a[2]+1;
a[5]=a[1]+a[2]+1;
a[i]=a[1]+a[2]+···+a[i/2]+1;(i为整数)

  这个可以用两重循环来模拟,一重做遍历,一重做累加。最后只要通过下标就能找到需要的值
PS.洛谷大佬题解
有些还看不太懂所以先码着

3.思路总结

  按一定的规律对数值进行处理或用递归能解但较复杂的题目可以考虑是否可以用递推法求解

P1036 选数

1.题目详情 洛谷P1036

2.实现方法

  在实现这题时,我觉得难点主要是在于如何实现对于列举选数的模拟,因为存在数组中的数顺序是固定的,而抽取其中一定数作累加这个过程是随机的,这就给模拟增加了思维上的难度。
  然而只要认识到从右往左抽取可以使过程相对固定(不用对数组进行处理只要改变长度就行),就使模拟难度降低。
  而从右往左不断抽取的过程是类似的,实现上也与汉诺塔问题很相似(调用函数的同时规模不断减小),所以可以考虑到需要用到递归的方法。
代码如下:

#include<stdio.h>
int a[5000001];
int s=0;
void ans(int sum){
	int i,j,k=1;
	for(i=2;i<sum;i++){
		if(sum%i==0) k=0;
	}
	if(k==1) s++;
}
void judge(int n,int k,int sum){
	int i;
	if(k==0){
		ans(sum);
	} 
	else{
		for(i=n-1;i>=k-1;i--){
			judge(i,k-1,sum+a[i]);
		}	
	}
}
int main(){
	int n,k,i;
	scanf("%d %d",&n,&k);
	for(i=0;i<n;i++){
		scanf("%d",&a[i]);
	}
	judge(n,k,0);
	printf("%d\n",s);	
			
}

3.思路总结

  如果发现在实现时有某个过程在不断重复但是规模却在不断增大或减少,可以考虑用递归来实现。

posted @ 2020-02-06 21:28  NoahQ  阅读(246)  评论(0编辑  收藏  举报