【算法】动态规划

其实对动态规划并不是特别了解,在网上看到说动态规划是递归时去除重复的运算,提高效率。

今天结合“数字三角形”这道编程题和书本内容进行学习,题目可以自行百度。

数字三角形这道题非常经典,通过三个方法来探讨这道题的解题思路~_~

首先申请两个常数组,a[i][j]存储输入数字三角形的数字,d[i][j]为二次计算存储的值。

其中状态转移方程是:d[i][j]=a[i][j]+max(d[i+1][j],d[i+1][j+1])。

方程及各方法的理解方法是直接代入数值跟着走一遍。

方法一:递归计算
int solve(int i,int j){
  return a[i][j]+(i==k?0:max(solve(i+1,j),solve(i+1,j+1))); //i==k?此处为边界判断
}
注:递归求解的过程有很多重复计算,效率低。得出的解存于a[1][1]中。


方法二:递推计算
int i,j;
for(j=1;j<=n;j++)d[n][j]=a[n][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]);
注:递推求解的思路清晰,从最下层一直往上推算,得出最优解,储存于d[1][1]中。时间复杂度是O(n^2)。


方法三:动态规划(记忆化搜索)
memset(d,-1,sizeof(d));
int solve(int i,int j){
  if(d[i][j]>=0)return d[i][j];
  return d[i][j]=a[i][j]+(i==k?0:max(solve(i+1,j),solve(i+1,j+1))); //i==k?此处为边界判断
}
注:对比方法一,不难发现d[i][j]的作用是标记重复计算,大大地优化了程序的时间开销。得出的最优解,储存于d[1][1]中。


送上方法三的解题源码

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int k;
int d[101][101],a[101][101];
int solve(int i,int j){
  if(d[i][j]>=0)return d[i][j];
  return d[i][j]=a[i][j]+(i==k?0:max(solve(i+1,j),solve(i+1,j+1)));
}
int main()
{
  memset(d,-1,sizeof(d));
  int i,j;
  cin>>k;
  for(i=1;i<=k;++i)
    for(j=1;j<=i;++j)
      cin>>a[i][j];
  solve(1,1);
  cout<<d[1][1]<<endl;
  return 0;
}

此时发现空间开销一半都是浪费的,可以动态申请二维数组,但相对麻烦。
动态申请二维数组的方法:
cin>>row>>col;
int **p=new int*[row];
for(int i=0;i<row;++i)
  p[i]=new int[col];

加油!!!

部分内容参考刘汝佳老师的《算法竞赛入门经典》

posted on 2016-02-27 10:38  Rnet  阅读(280)  评论(0编辑  收藏  举报

导航