动态规划【数塔初始篇之一】(原创)
【数塔】杭电2084
http://acm.hdu.edu.cn/showproblem.php?pid=2084
1.用递归的方法如下:
#include<stdio.h>
#define MAX_LEN 101
#define MAX(x,y) ((x > y) ? x : y )//计算两个数的最大值
int N,num[MAX_LEN][MAX_LEN];
int MaxSum(int i, int j)
{
if(i==N-1)//假如计算到最后一行,就直接返回
{
return num[i][j];
}
else//否则,计算该数下方临近的两个值,取大者
{
return num[i][j] + MAX(MaxSum(i+1,j), MaxSum(i+1,j+1));
}
}
int main()
{
int t,i,j;
scanf("%d", &t);
while((t--) && scanf("%d", &N))
{
for(i=0; i<N; i++)
{
for(j=0; j<=i; j++)
{
scanf("%d", &num[i][j]);//将数据读入二维数组
}
}
printf("%d\n", MaxSum(0,0));//递归计算数塔的最大值
}
return 0;
}
经过实验发现,计算的效率很不理想!为什么会这样?我们不妨简单的分析一下:
假如我们计算一个数MaxSum(i,j),就要调用函数,计算MaxSum(i+1,j)和MaxSum(i+1,j+1),比较二者的大小,取大者加上num[i][j]返回。只要稍微观察,我们就会发现,在计算MaxSum (i,j+1)的时候,又再一次调用MaxSum(i+1,j+1),重复计算就是这样产生的。
这样的例子你可能感觉不出什么,我们不妨将每调用一次MaxSum(i,j)称作在(i,j)位置上的一次计算,这样我们能得到一个调用次数的数塔:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
……
怎么样?是不是很熟?没错,就是传说中的杨辉三角!
计算一下总和:20+21+22+……+2N-1
这是多大的一个数……我想就不用我说了吧……
难道这道题不能用递归计算么?那倒也不是,只需我们将中间算过的数值保存即可……
#include<stdio.h>
#include<memory.h>
#define MAX_LEN 101
#define MAX(x,y) ((x > y) ? x : y )//计算两个数的最大值
int N;
int num[MAX_LEN][MAX_LEN];
int num_temp[MAX_LEN][MAX_LEN];
int MaxSum(int i, int j)
{
if(i==N-1)//假如计算到最后一行,就直接返回
{
return num[i][j];
}
else//否则,计算该数下方临近的两个值,取大者
{
if(-1==num_temp[i+1][j])//如果没计算过,就计算出结果并保留
{
num_temp[i+1][j] = MaxSum(i+1,j);
}
if(-1==num_temp[i+1][j+1])//如果没计算过,就计算出结果并保留
{
num_temp[i+1][j+1] = MaxSum(i+1,j+1);
}
return num[i][j] + MAX(num_temp[i+1][j], num_temp[i+1][j+1]);
}
}
int main()
{
int t,i,j;
scanf("%d", &t);
while((t--) && scanf("%d", &N))
{
memset(num_temp,-1,sizeof(num_temp));//初始化
for(i=0; i<N; i++)
{
for(j=0; j<=i; j++)
{
scanf("%d", &num[i][j]);//将数据读入二维数组
}
}
printf("%d\n", MaxSum(0,0));//递归计算数塔的最大值
}
return 0;
}
书上说:这种将一个问题分解成子问题递归求解,并且将中间结果保存避免重复计算的办法,就叫做“动态规划”。动态规划通常是用来求最优解的问题,能用动态规划求解的最优解问题,必须满足最优解每个局部解也都是最优的。以上题为例,最佳路径上面的每个数字到达底部都是最佳路径。
综上,我们可以发现动态规划就是一种递归的体现,它一种更加高效的递归方式,高效在于动态规划以空间换效率,保留了中间变量的值,从而减少大量的重复运算!个人觉得,动态规划是一种更加复杂的递归方式!
浙公网安备 33010602011771号