solve函数程序详解(NOIP2004 提高组)

博客详细解析了一道NOIP2004提高组竞赛中的solve函数程序,涉及递归调用和循环嵌套。通过逐步模拟程序执行过程,展示了递归如何通过栈来实现并最终得到结果。文章鼓励读者自行计算得出程序的输出答案328。
ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

此题为笔试题的读程序题。

题目程序代码如下:

#include<iostream>
using namespace std;
int number,ndata,data[100],sum;
void solve(int s,int sign,int n){
	int i;
	for(i=s;i<ndata;i++){
		sum+=sign*(number/n/data[i]);
		solve(i+1,-sign,n*data[i]);
	}
}
int main(){
	int i;
	cin>>number>>ndata;
	sum=0;
	for(i=0;i<ndata;i++) cin>>data[i];
	solve(0,1,1);
	cout<<sum<<endl;
	return 0;
} 

输入:1000 3 5 13 11

输出:

分析:此题是典型的for循环内插入递归调用,其实也可以转换成循环嵌套。在求解此题之前可以先缩小一下规模,寻找程序运行的方式。只要找到这个子问题的方式,那么这个题也就引刃而解了。

我们不如先把规模缩小。

​
#include<iostream>
using namespace std;
int number,ndata,data[100],sum;
void solve(int s,int sign,int n){
	int i;
	for(i=s;i<ndata;i++){
		sum+=sign*(number/n);
		cout<<"1."<<sum<<endl;//1代表调用递归时输出的结果
		solve(i+1,-sign,n*data[i]);
		cout<<"2."<<sum<<endl;//2表示调用递归结束后返回输出的结果
	}
}
int main(){
	int i;
	cin>>number>>ndata;
	sum=0;
	for(i=0;i<ndata;i++) cin>>data[i];
	solve(0,1,1);
      cout<<endl;
      cout<<sum<<endl;
	return 0;
}

运行此程序的结果为:

1000 3 5 13 11
1.1000
1.800
1.815
2.815
2.815
1.615
2.615
2.615
1.1615
1.1539
2.1539
2.1539
1.2539
2.2539

2539

那么现在开始模拟这个程序的执行过程:

 

首先,s,sign和n的值从主函数中传到子函数solve中的初值为0,1,1。

那么第一次执行的值为:

solve(0,1,1);
for(i=0;i<3;i++)
    sum=0+1*(1000/1)=1000;

然后调用函数,由递归式solve(i+1,-sign,n*data[i])知,此时变为solve(1,-1,1*data[0])=solve(1,-1,1*5)=solve(1,-1,5);

那么第二次执行的值为:

solve(1,-1,5);
for(i=1;i<3;i++)
    sum=1000-1*(1000/5)=800;

继续调用函数,此时变为solve(2,1,5*data[1])=solve(2,1,5*13)=solve(2,1,65);

那么第三次执行的值为:

solve(2,1,65);
for(i=2;i<3;i++)
    sum=800+1*(1000/65)=815;

继续调用函数,此时变为solve(3,-1,65);

但是,此时i=3,不符合循环条件,所以递归结束。开始返回。

 

返回:(P.S:学过的递归的oler应该都知道,递归是通过栈来实现,所以可得之前计算所产生的值都被压栈了。现在所要做的操作也就是弹栈。)

现在开始返回,由于最后一次有效递归是solve(2,1,65)。所以把最后一次递归所产生的值815带到上一层solve(1,-1,5)中。

此时执行的值为:

solve(1,-1,5);
for(i=1;i<3;i++)
    sum=815-1*(1000/5)=615;

此时sum的值为615。

这一次返回有效(“有效”意为可以进行运算)。

继续返回,这一次返回到了递归”头“(solve(0,1,1))

此时执行的值为:

solve(0,1,1);
for(i=1;i<3;i++)
    sum=1000+615=1615;

但现在还不能出来。还要重新进行新一轮递归。但运算方法与上面的一样。

此时执行的值为:

solve(1,-1,5);
for(i=2;i<3;i++)
    sum=1615-1*(1000/13)=1539;

接下来i=3,不符合条件,再一次返回。

这次返回到开头(solve(0,1,1))

此时执行的值为:

solve(0,1,1);
for(i=2;i<3;i++)
    sum=1000+1539=2539;

接下来i=3,不符合条件,再一次返回。可是这一次的位置已经是在开头,没有上层在继续返回,所以整个递归函数段结束。

 

然后就是输出2539了!

 

当然,原程序的运行原理也就是这样了(同理可得),至于答案是怎么算出来的,请读者自己去算一下。(不要怪我没说题目输出是328)

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值