【HDU 2013 猴子吃桃子】 尾递归与迭代

大一时的一道C语言练习题,可作为递归和尾递归转迭代的范例。HDU 2013 http://acm.hdu.edu.cn/showproblem.php?pid=2013

题意:猴子摘了sum个桃子,从第1天开始,每天吃掉剩余桃子的一半多一个,第n天时只剩1个桃子,求sum值。

分析:设第 i 天在开吃之前所剩的桃子数为sum(i),第 i 天要吃掉的桃子数为f(i),

则问题可表示为:已知sum(n)=1 和如下两个关系式:

  f(i) = sum(i)/2 + 1      (1)

  sum(i+1) = sum(i) - f(i)    (2)

  求sum(1)。

求解:(1)(2)式联立,可得递推式sum(i+1) = 2*sum(i) + 2。加上递归基sum(n)=1,可直接写出如下递归函数:

1 int sum(int x){
2     if(x==n) return 1;
3     return 2*sum(x+1) + 2;
4 }

在主函数中调用sum(1)即可得答案。

上面的递归函数属于尾递归(递归调用在最后一步),可以比较直观地转成迭代形式。只需从递归基出发进行n-1次迭代,即可得到同样的结果。代码如下:

1 ans=1;
2 int i=1;
3 while(i++ < n){
4     ans = 2*ans + 2;
5 }

这道题的迭代相比递归,省去了n-1层调用栈,空间复杂度从O(n)降到O(1),时间复杂度仍为线性的O(n)。

 

下面再来看一道尾递归转迭代的问题:Fibonacci数。

递推式 fib(n) = fib(n-1) + fib(n-2),递归基fib(0)=0, fib(1)=1。可写出如下递归函数:

1 int fib(int n){
2     if(n==0) return 0;
3     if(n==1) return 1;
4     return fib(n-1)+fib(n-2);
5 }

通过递归树分析,这一递归版包含了很多的重叠子问题,时间复杂度为O(2n),空间复杂度O(n)。

不过它同样属于尾递归,因而可以较方便地转为迭代版:

1 int fibI(int n){
2     int f=0, g=1;     // fib(0), fib(1)
3     int i=1;
4     while(i++ < n){
5         g = g + f;     // fib(n) = fib(n-1) + fib(n-2)
6         f = g - f;     // fib(n-1) = fib(n) - fib(n-2)
7     }
8     return g; // fib(n)
9 }

这里的两个变量f, g在每次迭代后都保存相邻两项fibonacci数,二者滚动向前(图片来自MOOC: TsinghuaX: 30240184X 数据结构(2015秋)),直至抵达最终的fib(n)。

此迭代版本只包含一个线性的while循环,因此时间复杂度为O(n),仅用两个变量暂存,故空间复杂度为O(1)。

时间: 2024-11-08 20:09:52

【HDU 2013 猴子吃桃子】 尾递归与迭代的相关文章

c语言 摘桃子问题

问题描述 c语言 摘桃子问题 输入文件(pea.in)第一行两个正整数m和n(n<=100m<=20),m为桃子的总数,n为朋友人数.第二行m个正整数,分别表示每个桃子的高度(每个桃子高度不超过300厘米).第三行n个正整数,分别表示每个朋友伸手能达到的高度(每个朋友伸手所能达到的最大高度不超过300厘米).输出文件(pea.out)一个整数,表示所有朋友最多能摘到的桃子总数. #include<stdio.h>int partition(int a[]int lowint hig

C++学习小结之语句_C 语言

一.顺序语句 二.条件,分支语句 1.if语句 关键是能够熟练运用 if的嵌套.要考虑好所有的情况. 如果说 条件是两种情况相互对应的,那么就可以只用 if 与else .但必须要想好 每个else 跟哪个if是一对. 如果情况是相互独立的三种情况以上,那么可以选择运用if ... else if ...else. 1.if语句 if(条件) { 满足条件的时候执行: } 2. if(条件) { 满足条件执行: } else { 不满足条件时执行: } 3 if(条件1) { 满足条件1的时候执

品牌营销需要有大数据、迭代创新和化整为零思维

对品牌营销而言,互联网思维的三大要点是大数据思维.迭代思维和将品牌建设由大变小.化整为零的思维模式.而在这其中,DSP则是最符合互联网思维的数字广告投放模式. 对品牌营销而言,互联网思维的三大要点是大数据思维.迭代思维和将品牌建设由大变小.化整为零的思维模式.而在这其中,DSP则是最符合互联网思维的数字广告投放模式. 自从2013年底新闻联播发布了关于"互联网思维带来了什么"的专题报道后,行业各界都对"互联网思维"展开了多样化的解读和讨论.作为互联网营销人,互联网思

线性递归和尾递归概述

今天一直在研究尾递归,看了些博文,记下点笔记,供以后复习用 线性递归:也即是普通递归,单向递归,线性递归函数的最后一步操作不是递归操作,而是其他的操作.当数据量很大的时候,会造成栈溢出,这是因为,在每次递归调用时,递归函数中的参数,局部变量等都要保存在栈中,如果数据量很大的话,便可能会溢出. 尾递归:也即是线性迭代,尾递归函数的最后一步操作是递归,也即在进行递归之前,把全部的操作先执行完,这样的好处是,不用花费大量的栈空间来保存上次递归中的参数.局部变量等,这是因为上次递归操作结束后,已经将之前

2013 腾讯马拉松专题

第一场 第一题 hdu4500 水题,直接模拟即可 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn = 25; int n , m; int num[maxn][maxn]; int ans[maxn][maxn]; int dir[4][2] = {{-1,0},{0,1},{1,0},

诊断 Java 代码: 提高 Java 代码的性能 尾递归转换能加快应用程序的速度,但不是所有的 JVM 都会做这种转换

简介: 很多算法用尾递归方法表示会显得格外简明.编译器会自动把这种方法转换成循环,以提高程序的性能.但在 Java 语言规范中,并没有要求一定要作这种转换,因此,并不是所有的 Java 虚拟机(JVM)都会做这种转换.这就意味着在 Java 语言中采用尾递归方法将导致巨大的内存占用,而这并不是我们期望的结果.Eric Allen 在本文中阐述了动态编译将会保持语言的语义,而静态编译则通常不会.他说明了为什么这是一个重要问题,并提供了一段代码来帮助判断您的即时(JIT)编译器是否会在保持语言语义的

递归与尾递归(C语言)

在计算机科学领域中,递归式通过递归函数来实现的.程序调用自身的编程技巧称为递归( recursion). 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解, 递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量.递归的能力在于用有限的语句来定义对象的无限集合. 一般来说,递归需要有:边界条件.递归前进段和递归返回段. 当边界条件不满足时,递归前进:当边界条件满足时,递归返回.

[JAVA软件工程师-面试宝典-2013最新版]

[JAVA面试宝典-2013最新版] 一. Java基础部分......................................................................................................2 1.一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?.....2 2.Java有没有goto?....................................................

TFS 2013 培训视频

最近给某企业培训了完整的 TFS 2013 系列课程,一共四天. 下面是该课程的内容安排: 项目管理     建立项目     成员的维护     Backlog 定义     任务拆分     迭代时间规划     工作量计划     任务分配 开发任务     工作区映射     任务调整与提交     任务挂起     编辑查询     代码提交(新添加解决方案.新文件.修改文件)     新建 BUG.修复并提交/解决 BUG.     代码审阅     冲突与合并     分支管理