动态规划之数字三角形

来源:互联网 发布:大陆网络女歌手排行榜 编辑:程序博客网 时间:2024/06/05 20:19

读北京大学李文新老师的《算法基础与在线实践》觉得动态规划这篇老师写的很好,就写了这篇博客,算是记笔记吧!
数字三角形问题:
如:
1
3 2
4 10 1
4 3 2 20

寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大,
路径上的每一步只能往左下或者右下走。
输入格式:
1
3 2
4 10 1
4 3 2 20
分析:我们可以用一个二维数组来存储这个数字三角形。D(i,j)表示第i行j列。i,j从1开始算。MaxSum(i, j)表示从D(i,j)到底边的各条路径中,最佳路径的数字之和。则问题就变成了求MaxSum(1,1)。
1.递归法:

#include <iostream>#include <algorithm>#define Max 101 using namespace std;int D[Max][Max];    //定义矩阵大小 int n;  //行数 int MaxSum(int i,int j){ //递归求某个子问题     if(n==i){        return D[i][j];    }    int x=MaxSum(i+1,j);//左下    int y=MaxSum(i+1,j+1);//右下    return max(x,y)+D[i][j];}int main(int argc, char** argv) {    int i,j;    cin>>n;    for(i=1;i<=n;i++){        for(j=1;j<=i;j++){            cin>>D[i][j];        }    }    cout<<MaxSum(1,1)<<endl;    return 0;}

不过这种做法需要不停的递归调用函数,而且会重复计算已经计算过的结果。对运行时间提出了极大的要求,很显然这不是很好的算法。

2.记忆型递归! 为了解决重复计算问题,我们将已经计算过的值用一个二维数组存储起来,当我们计算某结点时,先判断这个值是否已经计算过,如果计算过,则直接将这个值返回即可!当然这个二维数组要与我们用于存储的三角形数字的那个二维数组同等大小。

#include <iostream>#include <algorithm>#define Max 101using namespace std;int n;//行数int D[Max][Max];//定义矩阵大小int maxSum[Max][Max];//用于存储计算过的结果int MaxSum(int i,int j){    if(maxSum[i][j]!=-1)//已经计算过        return maxSum[i][j];    if(i==n)        return D[i][j];    int x=MaxSum(i+1,j);    int y=MaxSum(i+1,j+1);    maxSum[i][j]=max(x,y)+D[i][j];    return maxSum[i][j];}int main(int argc, char** argv){    int i,j;    cin>>n;    for(i=1;i<=n;i++){        for(j=1;j<=i;j++){            cin>>D[i][j];            maxSum[i][j]=-1;//没有计算过的标志为-1        }    }    cout<<MaxSum(1,1)<<endl;    return 0;}

3.动态规划的思想!由于以上两种情况皆使用了递归,在计算机中调用函数是很耗内存的,所以我们使用一种不调用函数的方法,递推法!

#include <iostream>#include <algorithm>#define Max 101using namespace std;int D[Max][Max];//定义矩阵大小int n;//行数int maxSum[Max][Max];////用于存储计算过的结果int main(int argc, char** argv){    int i,j;    cin>>n;    for(i=1;i<=n;i++){        for(j=1;j<=i;j++){            cin>>D[i][j];        }    }    for(i=1;i<=n;i++)//将最后一行赋值到maxSum[n][i] i=1~n         maxSum[n][i]=D[n][i];    for(i=n-1;i>=1;i--){//递推求maxSum[i][j]         for(j=1;j<=i;j++){            maxSum[i][j]=max(maxSum[i+1][j],maxSum[i+1][j+1])+D[i][j];//自底向上递推        }       }    cout<<maxSum[1][1]<<endl;     return 0;}
原创粉丝点击