分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
递归和递推都是算法设计中的难点,算法又十分相近,很多和我一样学生误认为是一回事,非常容易混淆。其实它们之间既有相似点,又有明显的区别。
递推一般用循环来解决,从已知条件到未知逐渐接近结果;
(1)将复杂运算分解为若干重复的简单运算
(2)后一步骤建立在前一步骤之上
(3)计算每一步骤的方法相同
(4)从开始向后计算出结果
(5)使用循环结构,通过多次循环逐渐逼近结果
递归一般自己调用自己,从未知到已知,把规模大的、较难解决的问题变成规模较小的、易解决的同一问题。规模较小的问题又变成规模更小的问题,并且小到一定程度可以直接得出它的解,从而得到原来问题的解。
(1)每一次递归都缩小问题规模,直到问题足够小
(2)使用选择分支语句
(3)从后往开始逐步逼近
(4)达到最开始,再把初始值带入往后逐一求解
下面通过例子逐个介绍。
递推:
一。 解阶乘 n! = 1*2*3*4*....*(n-1)*n.
fun(int n) { long s=1; int i; for(i=1;i<=n;i++) s=s*i; return s; }
二。捕鱼问题
A,B,C,D,E五个渔夫夜间合伙捕鱼,,第二天清A先醒来,他把鱼均分五份,把多余的一条扔回湖中,便拿了自己的一份回家了,B醒来后,也把鱼均分五份,把多余的一条扔回湖中,便拿了自己的一份回家了,C,D,E也按同样方法分鱼。问5人至少捕到多少条鱼?
这也是一个递推问题,递推关系式为 F(n+1) = F(n)*5/4+1 (i = 1,2,3,4) F(5)即捕鱼的总数
#include <stdio.h>int main(){ int i, n, f[5], flag; flag = 1; n = 1; while (flag == 1) { f[0] = 5*n+1; flag = 0; for (i=1; i<5; i++) { if (f[i-1]%4!=0) { flag=1; break; } f[i] = 5*f[i-1]/4+1; } n++; } printf("%d\n",f[4]); return 0;}
三。平面分割
#include <stdio.h>int main(){ int i, n, f2, f1; while (1) { scanf("%d",&n); if (n==0) { break; } f1 = 2; for (i=1; i<=n; i++) { f2 = f1+2*(i-1); f1 = f2; } printf("%d\n",f2); } return 0;}
递归:
一。计算组合数
问题:计算组合数C(10,3)(组合数:从n个不同元素中,任取m(m≤n)个元素并成一组,叫做从n个不同元素中取出m个元素的一个组合;从n个不同元素中取出m(m≤n)个元素的所有组合的个数,叫做从n个不同元素中取出m个元素的组合数。)
我们可以利用组合恒等式:
#include <stdio.h>int Cmn(int m, int n ){ if (m<0 || m<n || n<0) { return 0; } if (m==n) { return 1; } if (n==1) { return m; } return Cmn(m-1,n)+Cmn(m-1,n-1);}int main(){ printf("C(10,3) = %d \n",Cmn(10,3)); return 0;}
long ff(int n){ long f; if(n<0) printf("n<0,input error"); else if(n==0||n==1) f=1; else f=ff(n-1)*n; return(f);}main(){ int n; long y; printf("\ninput a inteager number:\n"); scanf("%d",&n); y=ff(n); printf("%d!=%ld",n,y);}
三。Hanoi 汉诺塔问题
本题算法分析如下,设A上有3个盘子:
1将A上的2个圆盘移到B
2将A上的1个圆盘直接移到C
3将B上的2个圆盘移到C其中第2步可以直接实现
将第1步分解:(借助C)
1.1 将A上的一个圆盘从A移到C
1.2 将A上的一个圆盘从A移到B
1.3 将C上的一个圆盘从C移到B
将第3步分解:(借助A)
3.1 将B上的一个圆盘从B移到A
3.2 将B上的一个圆盘从B移到C
3.3 将A上的一个圆盘从A移到C
由此可知,将3个圆盘从A移到C,需要7步,将n个圆盘从A移到C需要2的n次方减1步,要进行第n步,需要先进行第n-1步,可分为3个步骤
1将A上n-1个圆盘借助C移到B
2将A上剩下的1个圆盘直接移到C
3将B上n-1个圆盘借助A移到C
- <code class="language-cpp">#include <stdio.h>
- void Move(int n,char a,char b)
- {
- printf("%d:%c-->%c\n",n,a,b);
- }
- void Hanoi(int n,char a,char b,char c)
- {
- if(n==1)//将A上的1个圆盘直接移到C,递归退出条件
- Move(n,a,c);
- else
- {
- Hanoi(n-1,a,c,b);//将A上n-1个圆盘借助C移到B
- Move(n,a,c);//将A上剩下的1个圆盘直接移到C
- Hanoi(n-1,b,a,c);//将B上n-1个圆盘借助A移到C
- }
- }
- int main()
- {
- int n;
- printf("\ninput number:");
- scanf("%d",&n);
- Hanoi(n,'A','B','C');
- return 0;
- }
- /* 打印结果
- input number:3
- 1:A-->C
- 2:A-->B
- 1:C-->B
- 3:A-->C
- 1:B-->A
- 2:B-->C
- 1:A-->C
- */</code>
#include <stdio.h>void Move(int n,char a,char b){ printf("%d:%c-->%c\n",n,a,b);}void Hanoi(int n,char a,char b,char c){ if(n==1)//将A上的1个圆盘直接移到C,递归退出条件 Move(n,a,c); else { Hanoi(n-1,a,c,b);//将A上n-1个圆盘借助C移到B Move(n,a,c);//将A上剩下的1个圆盘直接移到C Hanoi(n-1,b,a,c);//将B上n-1个圆盘借助A移到C }}int main(){ int n; printf("\ninput number:"); scanf("%d",&n); Hanoi(n,'A','B','C'); return 0;}/* 打印结果 input number:3 1:A-->C 2:A-->B 1:C-->B 3:A-->C 1:B-->A 2:B-->C 1:A-->C*/
下面通过一个具体例子比较一下递归和递推。
long f(int n){ if(n<=2) return 1; else return f(n-1)+f(n-2);}
递推解:
long f(int n){ long t;f1=1,f2=1; if(n<=2) reutrn 1; for(int i=3;i<=n;i++) { t=f1+f2; f1=f2; f2=t; } }
由此可见,递归重在“归”,你要求的是什么,就直接求什么,至于要怎么去调用、怎么去求,让函数自己一步一步去反复调用;递推重在“推”,是按照我们平时做数学的方法来算。编程时递归比较特殊, 表现 在函数自身调用自身,这样编程代码紧凑,程序的可读性好,但效率低,还可能导致堆栈溢出,特别是递归层次比较多时。一般来说,递归程序都可以用循环程序实现,用循环程序实现虽然较难理解,但 安全 可靠。