目录
一.分治法和动态规划的关系总结
分治算法 | 动态规划算法 | 备忘录算法 | |
相同点 | 分解原问题 | 分解原问题 | |
构造递归方程 | 构造递归方程 | ||
不同点 | 自顶向下递归 | 自底向上递推 | 自顶向下递归 |
子问题相互独立 | 子问题重叠 | 子问题重叠 | |
程序结构简单 | 保存已解决的子问题 | 保存已解决的子问题 | |
时间复杂度高 | 时间复杂度低 | 时间复杂度低 |
二.备忘录方法
1.是动态规划的变形
2.用一个表保存已解决的子问题容案、再遇到子间题时,只要查看该子题的解,而不必重新求解。
3.控制结构与动态规划算法不同,备忘录使用自顶向下的递归方式与直接递归方法相同。
4.计算思路
(1)为每个子问题建立一个记录项
(2)初始化时,记录存入一个特殊的值,表示该问题尚未求解。
(3)在求解时,对碰到的每个子问题先查看其相应的记录项,若是特殊值表示还未求 解过,需要求解并保存结果否则直接取出问题的解。
5.
相同点:都利用了子问题重叠性质,对每个子问题两种算法都只计算一次并记录答案,再碰到相同的问题是直接取用已得到的答案。
不同点:控制结构不同适用情况,当子问题空间中的部分子问题不必求解时,用备忘录方法效率较高,因为该方法只解决那些确实需要求解的子问题。
三.数字三角形路径问题
给定等腰直角数字三角形,请确定从顶至底的某个位置的一条路径,使该路径所经过的数字的总和最大。假设每一步可延直线向下或右斜线向下走。
使用备忘录方法解决数字三角形问题,求解最大数字和、以及其对应的路径。
#include<iostream>
#include<stdlib.h>
using namespace std;
const int m=5;
int v[m][m];
int M[m][m];
int lookuptriag(int i,int j){
int u1,u2;
if(M[i][j]>0)
return M[i][j];
if(i==0 && j==0){
return M[i][j]=v[i][j];
if(i==j){
cout<<i<<j<<M[i][j]<<endl;
M[i][j]=lookuptriag(i-1,j-1)+v[i][j];
return M[i][j];
}else{
if(i>j){
if(i!=0 && j==0){
M[i][j]=lookuptriag(i-1,j)+v[i][j];
cout<<i<<j<<M[i][j]<<endl;
}else{
u1=lookuptriag(i-1,j);
u2=lookuptriag(i,j-1);
M[i][j]=u1>u2?u1+v[i][j]:u2+v[i][j];
return M[i][j];
}
}
}
}
}
void TrackSolution(int i,int j){
printf("%d,%d\n",i,j);
while(i!=0 ||j!=0){
if(i==0){
j--;
printf("%d,%d\n",i,j);
}else{
if(j==0){
i--;
printf("%d,%d\n",i,j);
}else{
if(M[i-1][j]>=M[i][j-1]){
i--;
printf("%d,%d\n",i,j);
}else{
j--;
printf("%d,%d\n",i,j);
}
}
}
}
}
int main(){
int i,j,start,end,t,count;
printf("随机生成数字三角形如下:\n");
for(i=0;i<m;i++){
for(j=0;j<=i;j++){
v[i][j]=rand()%10;
M[i][j]=-1;
printf("%d\t",v[i][j]);
}
printf("\n");
}
count=lookuptriag(m-1,m-1);
printf("备忘录m三角形如下:\n");
for(i=0;i<m;i++){
for(j=0;j<=i;j++){
printf("%d\t",M[i][j]);
}
printf("\n");
}
printf("追总解如下\n");
TrackSolution(m-1,m-1);
return 1;
}