递推(一):递推法的基本思想

所谓递推,是指从已知的初始条件出发,依据某种递推关系,逐次推出所要求的各中间结果及最后结果。其中初始条件或是问题本身已经给定,或是通过对问题的分析与化简后确定。

利用递推算法求问题规模为n的解的基本思想是:当n=1时,解或为已知,或能非常方便地求得;通过采用递推法构造算法的递推性质,能从已求得的规模为1、2、…、i−1的一系列解,构造出问题规模为i的解。这样,程序可从i=0或i=1出发,重复地由已知至i−1规模的解,通过递推,获得规模为i的解,直至获得规模为n的解。

可用递推算法求解的问题一般有以下两个特点: (1) 问题可以划分成多个状态; (2) 除初始状态外,其它各个状态都可以用固定的递推关系式来表示。当然,在实际问题中,大多数时候不会直接给出递推关系式,而是需要通过分析各种状态,找出递推关系式。

利用递推算法解决问题,需要做好以下四个方面的工作:

(1)确定递推变量

应用递推算法解决问题,要根据问题的具体实际设置递推变量。递推变量可以是简单变量,也可以是一维或多维数组。从直观角度出发,通常采用一维数组。

(2)建立递推关系

递推关系是指如何从变量的前一些值推出其下一个值,或从变量的后一些值推出其上一个值的公式(或关系)。递推关系是递推的依据,是解决递推问题的关键。有些问题,其递推关系是明确的,大多数实际问题并没有现成的明确的递推关系,需根据问题的具体实际,通过分析和推理,才能确定问题的递推关系。

(3)确定初始(边界)条件

对所确定的递推变量,要根据问题最简单情形的数据确定递推变量的初始(边界)值,这是递推的基础。

(4)对递推过程进行控制

递推过程不能无休止地重复执行下去。递推过程在什么时候结束,满足什么条件结束,这是编写递推算法必须考虑的问题。

递推过程的控制通常可分为两种情形:一种是所需的递推次数是确定的值,可以计算出来;另一种是所需的递推次数无法确定。对于前一种情况,可以构建一个固定次数的循环来实现对递推过程的控制;对于后一种情况,需要进一步分析出用来结束递推过程的条件。

递推通常由循环来实现,一般在循环外确定初始(边界)条件,在循环中实施递推。

递推法从递推方向可分为顺推与倒推。

所谓顺推法是从已知条件出发,通过递推关系逐步推算出要解决的问题的结果的方法。如求斐波拉契数列的第20项的值,设斐波拉契数列的第n项的为f(n),已知f(1)=1,f(2)=1;通过递推关系式f(n)=f(n-2)+f(n-1) (n>=3,n∈N),可以顺推出f(3)=f(1)+f(2)=2、f(4)=f(2)+f(3)=3、…直至要求的解f(20)=f(18)+f(19)=6765。

所谓倒推法,就是在不知初始值的情况下,经某种递推关系而获知了问题的解或目标,从这个解或目标出发,采用倒推手段,一步步地倒推到这个问题的初始情况。

一句话概括:顺推是从条件推出结果,倒推从结果推出条件。

顺推法是从前往后推,从已求得的规模为1、2、…、i−1的一系列解,推出问题规模为i的解,直至得到规模为n的解。顺推算法可描述为:

for (k=1; k<=i−1; k++)

f[k]= <初始值>;               // 按初始条件,确定初始值

for (k=i; k<=n; k++)

f[k]= <递推关系式>;       // 根据递推关系实施递推

cout<<f[n];                   // 输出n规模的解f(n)

倒推法是从后往前推,从已求得的规模为n、n−1、…、i+1的一系列解,推出问题规模为i的解,直至得到规模为1的解(即初始情况)。倒推算法可描述为:

for (k=n; k>=i+1; k--)

f[k]= <初始值>;               // 按初始条件,确定初始值

for (k=i; k>=1; k--)

f[k]= <递推关系式>;       // 根据递推关系实施递推

cout<<f[1];                   // 输出问题的初始情况f(1)

递推问题一般定义一维数组来保存各项推算结果,较复杂的递推问题还需定义二维数组。例如,当规模为i的解为规模为1、2、…、i−1的解通过计算处理决定时,可利用二重循环处理这一较为复杂的递推。

【例1】RPG涂色问题

有排成一行的n个方格,用红(Red)、粉(Pink)、绿(Green)三种颜色涂每个格子,每个格子涂一种色,要求任何相邻的方格不能同色,且首尾两格也不同色。

编写一个程序,输入方格数n(0<n<=30),输出满足要求的全部涂法的种数。

(1) 编程思路

设满足要求的n个方格的涂色方法数为F(n)。

因为RPG有三种颜色,可以先枚举出当方格数为1、2、3时的涂法种数。

显然,     F(1)=3   (即R、P、G三种)

F(2)=6   (即RP、RG、PR、PG、GR、GP六种)

F(3)=6   (即RPG、RGP、PRG、PGR、GRP、GPR六种)

当方格的个数大于3时,n个方格的涂色方案可以由n-1方格的涂色方案追加最后一个方格的涂色方案得出,分两种情况:

1)对于已按要求涂好颜色的n-1个方格,在F(n-1)种合法的涂色方案后追加一个方格(第n个方格),由于合法方案的首尾颜色不同(即第n-1个方格的颜色不与第1个方格的相同),这样,第n个方格的颜色也是确定的,它必定是原n-1个方格的首尾两种颜色之外的一种,因此,在这种情况下的涂色方法数为F(n-1)。

2)对于已按要求涂好颜色的n-2个方格,可以在第n-1个方格中涂与第1个方格相同的颜色,此时由于首尾颜色相同,这是不合法的涂色方案,但可以在第n个方格中涂上一个合法的颜色,使其成为方格长度为n的合法涂色方案(注意:当n等于3时,由于第1(3-2)个方格与第2(3-1)个方格颜色相同,第3个方格不论怎样涂都不会合法,因此递推的前提是n大于3),在第n个方格中可以涂上两种颜色(即首格外的两种颜色,因为与它相连的第n-1个方格和第1个方格的颜色是一样的),因此,在这种情况下的涂色方法数为2*F(n-2)。

由此,可得递推公式:F(n)= F(n-1) + 2*F(n-2)  (n>=4)

程序中定义3个变量f1、f2和f3分别表示F (n-2)、F(n-1)和F(n),初始时f1=6、f2=6。

当n<4时,根据初始情况直接输出结果。

当n>=4时,用循环递推计算F(n)。程序段描述为:

for(i=4;i<=n;i++)

{

f3=f1+f2;          // 计算当前F(i)

f1=f2;   f2=f3;    // 为下一次递推做准备

}

(2)源程序及运行结果

#include <iostream>

using namespace std;

int main()

{

int i,n,f1,f2,f3,num;

cout<<"请输入方格的数目 n (0<n<=30):";

cin>>n;

if (n==1)  num=3;

else if (n==2 || n==3)  num=6;

else

{

f1=6;  f2=6;

for(i=4;i<=n;i++)

{

f3=2*f1+f2;         // 递推求F(i)

f1=f2;  f2=f3;       // 为下次递推做准备

}

num=f3;

}

cout<<n<<"个方格的正确涂色方案一共有"<<num<<"种。"<<endl;

return 0;

}

为更清晰地描述递推过程并保存中间结果,可以定义一个一维数组f[31],数组元素f[i]保存总数为i个方格的涂色方法数。初始值: f[1]=3、f[2]=6、f[3]=6。源程序清单如下。

#include <iostream>

using namespace std;

int main()

{

int i,n,f[31];

f[0]=0;

f[1]=3;

f[2]=6;

f[3]=6;

for(i=4;i<31;i++)

f[i]=f[i-1]+2*f[i-2];

cout<<"请输入方格的数目 n (n<=30):";

cin>>n;

cout<<n<<"个方格的正确涂色方案一共有"<<f[n]<<"种。"<<endl;

return 0;

}

原文地址:https://www.cnblogs.com/cs-whut/p/11022438.html

时间: 2024-11-14 02:34:16

递推(一):递推法的基本思想的相关文章

atitit.web 推送实现方案集合(2)---百度云,jpush 极光推送 ,个推的选型比较.o99

atitit.web 推送实现方案集合(2)---百度云,jpush 极光推送 ,个推的选型比较.o99 1.1. 云推送有推送次数或频率的限制吗? 1 1.2. 推送的消息长度 1 1.3. 离线消息的支持 2 1.4. 是否支持转义字符 2 2. 客户端身份识别机制 2 3. 绑定客户端的区别流程::jpush胜出 2 4. 文档风格比较::百度,jpush胜出 3 5. 编程sdk框架比较..个推,百度胜出 3 6. 编程风格的比较 3 6.1. 个推 3 6.2. 百度 4 6.3. J

第三方推送-个推使用

个推的使用在Android客户端相对来说使用比较简单,已经提供了sdk Demo,按照文档和Demo配置相关代码就可以.下图为推送的示意图 客户端需要区分通知和透传的使用,根据需求告诉服务端选择不同的模板 服务端注意的东西相对来说比较多: 个推每天的消息推送量数以亿计,统计分析日志时,经常可以从日志规律发现调用方的一些使用误区,今天提几点开发者在使用个推api时易出现的几个误区. 误区一 推送选错接口 个推服务端adk提供给开发者三个推送接口:pushMessageToSingle/ pushM

IOS 之消息推送(个推)---个人小结

前言:自从上个星期开始整这个推送,弄了差不多一个星期,今天终于给整好了,因此现在来记录这段"奇妙"的旅程. 我们公司使用的消息推送是用的第三方--个推,这里不得不说一下,个推的技术人员还是蛮热心的,一直在帮助我排查问题,终于问题解决了,感谢感谢! 步骤及问题排查: 1.参照开发文档,集成SDK ,这里就不一一介绍了.(注意,个推的ios推送只能使用透传) 2.创建证书.苹果的推送证书分为开发证书(测试用)和生产证书(上线用).这里需要注意的就是,创建证书之前先必须打开证书的push 服

什么是推送,推送的原理是什么

网页推送,是指将经过整理的信息资源以网页的形式迅速转发至用户的界面,实现用户的多层次需求,使得用户能够自己设定所需要的信息频道,并直接在用户端接收定制信息的实现方式. 用很直接的话来说就是把最新的软件信息,资讯或者别人想让你看到的东西推荐给你,就像是腾讯新闻的最新热点弹窗一样的作用. 这里有移动开发市场上经常用的推送服务,推送服务,你也可以通过他们的特点和配置过程了解对比下,另外还有推送界的十大豪门推送. 推送方案的公认评价采取4s标准: 1.Safe(安全) 2. Stable(稳定) 3.S

什么是推送,推送的原理是什么?

网页推送,是指将经过整理的信息资源以网页的形式迅速转发至用户的界面,实现用户的多层次需求,使得用户能够自己设定所需要的信息频道,并直接在用户端接收定制信息的实现方式. 用很直接的话来说就是把最新的软件信息,资讯或者别人想让你看到的东西推荐给你,就像是腾讯新闻的最新热点弹窗一样的作用. 这里有移动开发市场上经常用的推送服务,推送服务,你也可以通过他们的特点和配置过程了解对比下,另外还有推送界的十大豪门推送. 推送方案的公认评价采取4s标准: 1.Safe(安全) 2. Stable(稳定) 3.S

Android实现点击通知栏后,先启动应用再打开目标Activity ,极光推送等推送的也可以参考一下(转)

我因为项目中集成了极光推送,推送的通知栏点开需要确定进入哪个界面就参考了这边文章,感谢作者的无私. 情况简述 在开发Android app的过程中,遇到这样一个需求:app中启动一个Service,该Service在独立进程中运行,与服务器保持长连接,将服务器推送过来的消息在通知栏中显示,并设置点击动作,点击后跳转到app中对应的Activity.目前遇到的问题是Service以独立进程运行,在收到消息并弹出通知后,app本身的进程有两种情况: app正在运行 app已退出 对于第一种情况,处理

C# 数据推送 实时数据推送 轻量级消息订阅发布 多级消息推送 分布式推送

前言 本文将使用一个NuGet公开的组件技术来实现数据订阅推送功能,由服务器进行推送数据,客户端订阅指定的数据后,即可以接收服务器推送过来的数据,包含了自动重连功能,使用非常方便 nuget地址:https://www.nuget.org/packages/HslCommunication/            github地址:https://github.com/dathlin/HslCommunication                                 如果喜欢可以s

java SDK服务端推送 --极光推送(JPush)

网址:https://blog.csdn.net/duyusean/article/details/86581475 消息推送在APP应用中越来越普遍,来记录一下项目中用到的一种推送方式,对于Andriod它并没有自己的原生推送机制,一种简单的推送方式是采用第三方推送服务的方式,即通过嵌入SDK使用第三方提供的推送服务,主流的有百度云推送,极光推送,友盟,个推.亚马逊等等.本篇博文只介绍采用极光推送的方式.        如果你是一个新手,建议你先看完本篇博客,然后在去看官网,这样也许上手会快一

SEO教程:快速增加360搜索引擎收录,360自动推送批量推送版

上次改编了一下百度的JS推送代码,实现了批量推送 传送门>>>百度链接提交-js代码推送批量推送版 这次我们来研究360js自动推送代码. <script> (function(){ var src = "https://jspassport.ssl.qhimg.com/11.0.1.js?d182b3f2654654f2db83acfaaf6e696dba"; document.write('<script src="' + src +