您的位置:首页 > 其它

数字三角——递归、递归、内存搜索

2015-07-25 14:45 369 查看

数字三角

叙述性说明:

有一个非负整数三角,第一行中只有一个号码,的左下方和右下方各有一个数。

问题:

从第一行的数開始。每次能够往左下或右下走一格。直到走到最下行,把沿途经过的数所有加起来。

怎样走才干使得这个和尽量大?



分析:

不难看出此题是一个动态的决策问题:每次有两种选择——左下或右下。

假设用回溯法求出全部的可能的路线,就能够从中选出最优的路线。但和往常一样,回溯法的效率太低:一个n层数字三角形的完整路线有2^n条。当n非常大时回溯法的速度将让人无法忍受。因此本题讨论用递归,递推及记忆化搜索的方法实现,尽管还有其它的方法,但此时仅仅讨论学习比較相似的这几种方法。

最先想到的是递归实现:

#include "stdio.h"
#define maxn 100
int a[maxn][maxn],n;

inline max(int x,int y)
{
return x>y?x:y;
}

//递归计算实现
int d(int x,int y)
{
return a[x][y]+(x==n?

0:max(d(x+1,y),d(x+1,y+1)));
}

int main()
{
while(~scanf("%d",&n))
{
int i,j;
for(i=1;i<=n;i++){
for(j=1;j<=i;j++)
scanf("%d",&a[i][j]);
}

printf("max:%d\n",d(1,1));

}
return 0;
}
尽管这样做是正确的,但时间效率太低。其原因在于反复计算。

例: 在下列计算中d(3,2)被反复调用

d(2,1) 的计算会调用--> d(3,1) , d(3,2)

d(2,2) 的计算会调用--> d(3,2) , d(3,3)

递推的实现:

#include "stdio.h"
#define maxn 100
int a[maxn][maxn],n;

inline max(int x,int y)
{
return x>y?

x:y;
}

//递推实现
int d(int x,int y)
{
int d

,i,j;
for(j=1;j<=n;j++) d
[j]=a
[j];
for(i=n-1;i>=1;i--){
for(j=1;j<=i;j++)
d[i][j]=a[i][j]+max(d[i+1][j],d[i+1][j+1]);
}

return d[x][y];
}

int main()
{
while(~scanf("%d",&n))
{
int i,j;
for(i=1;i<=n;i++){
for(j=1;j<=i;j++)
scanf("%d",&a[i][j]);
}
printf("max:%d\n",d(1,1));
}
return 0;
}


记忆化搜索实现:

#include "stdio.h"
#include "string.h"
#define maxn 100
int a[maxn][maxn],n;
int d[maxn][maxn];	//记忆化搜索所使用的状态记忆数组
inline max(int x,int y)
{
return x>y?x:y;
}

/*
记忆话搜索。程序分成两部分。首先  memset(d,-1,sizeof(d)); 把d所有初始化为-1,
然后编写递归函数:
*/
int distance(int i,int j)
{
if(d[i][j]>=0) return d[i][j];
return d[i][j]=a[i][j]+(i==n?0:max(distance(i+1,j),distance(i+1,j+1)));
}
/*
上述程序依旧是递归的,但同一时候也把计算结果保存在数组d中。题目中说各个数都是非负的,因此
假设已经计算过某个d[i][j]。则它应是非负的,这样。仅仅需把所有d初始化为-1,就可以通过推断是否
d[i][j]>=0得知是否已经被计算过。
*/

int main()
{
while(~scanf("%d",&n))
{
int i,j;
for(i=1;i<=n;i++){
for(j=1;j<=i;j++)
scanf("%d",&a[i][j]);
}
memset(d,-1,sizeof(d));	//状态记忆化数组初始化
printf("max:%d\n",distance(1,1));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: