动态规划算法总结及实例简介
2016-06-24 19:48
225 查看
动态规划特点:
1. 把原始问题划分为一系列子问题。
2. 求解每个子问题仅一次,并将其结果保存在一个表中,以后用到时直接存取,不重复计算,节省时间。
3. 自底向上的计算。
适用范围:
一类优化问题:可分为多个相关子问题,子问题的解被重复适用。
适用动态规划的条件:
1. 优化子结构
a. 当一个问题的最优解包含了子问题的优化解时,我们说这个问题具有优化子结构。
b. 缩小子问题集合,只需那些优化问题中包含的子问题,降低实现复杂性。
c. 优化子结构使得我们能自下而上地完成求解过程
2. 重叠子问题
在问题的求解过程中,很多子问题的解将被多次使用。
动态规划的设计模式:
1. 分析优化解的结构
2. 递归地定义最优解的代价
3. 自底向上地计算优化解的代价并保存之,并获取构造最优解的信息。
4. 根据最优解的信息构造优化解
实例简介(参考算法导论教材第15章):
1. 装配线调度问题:
2. 矩阵乘法问题:
3. 最长公共子序列问题:
1. 把原始问题划分为一系列子问题。
2. 求解每个子问题仅一次,并将其结果保存在一个表中,以后用到时直接存取,不重复计算,节省时间。
3. 自底向上的计算。
适用范围:
一类优化问题:可分为多个相关子问题,子问题的解被重复适用。
适用动态规划的条件:
1. 优化子结构
a. 当一个问题的最优解包含了子问题的优化解时,我们说这个问题具有优化子结构。
b. 缩小子问题集合,只需那些优化问题中包含的子问题,降低实现复杂性。
c. 优化子结构使得我们能自下而上地完成求解过程
2. 重叠子问题
在问题的求解过程中,很多子问题的解将被多次使用。
动态规划的设计模式:
1. 分析优化解的结构
2. 递归地定义最优解的代价
3. 自底向上地计算优化解的代价并保存之,并获取构造最优解的信息。
4. 根据最优解的信息构造优化解
实例简介(参考算法导论教材第15章):
1. 装配线调度问题:
#include <iostream> using namespace std; int main(){ int m[2][6]={0};//记录装配的时间代价 int s[2][6]={0};//记录装配的路径选择 int a[2][6]={{7,9,3,4,8,4},{8,5,6,4,5,7}}; int e1=2,e2=4,x1=3,x2=2; int t[2][5]={{2,3,1,3,4},{2,1,2,2,1}}; m[0][0]=e1+a[0][0]; m[1][0]=e2+a[1][0]; for(int j=1;j<6;j++){ for(int i=0;i<2;i++){ int temp1=m[1-i][j-1]+t[1-i][j-1]+a[i][j]; int temp2=m[i][j-1]+a[i][j]; if(temp1<temp2){ m[i][j]=temp1; s[i][j]=1-i+1; } else{ m[i][j]=temp2; s[i][j]=i+1; } } } for(int i=0;i<2;i++){ for(int j=0;j<6;j++){ cout<<m[i][j]<<" "; } cout<<endl; } for(int i=0;i<2;i++){ for(int j=0;j<6;j++){ cout<<s[i][j]<<" "; } cout<<endl; } int line; for(int i=5;i>=0;i--){ if(i==5){ if(m[0][i]+x1<m[1][i]+x2){ cout<<"The shortest time consuming is "<<m[0][i]+x1<<endl; cout<<"line:"<<endl; line=0; cout<<line+1<<" "; } else{ cout<<"The shortest time consuming is "<<m[1][i]+x2<<endl; cout<<"line"<<endl; line=1; cout<<line+1<<" "; } } cout<<s[line][i]<<" "; line=s[line][i]-1; } cout<<endl; }
2. 矩阵乘法问题:
#include <iostream> #include <string> using namespace std; void PrintOptimal(int s[][6],int i,int j){//打印优化解结果 if(i==j) cout<<i+1; else{ cout<<'('; PrintOptimal(s,i,s[i][j]-1); PrintOptimal(s,s[i][j],j); cout<<')'; } } int main(){ int p[7]={30,35,15,5,10,20,25}; int m[6][6]={0};//记录乘积计算代价 int s[6][6]={0};//记录k值选择标记 const int n=6; for(int i=1;i<n;i++){ for(int j=0;j<n-i;j++){ int temp=1000000; for(int k=j;k<j+i;k++){ int tmp=m[j][k]+m[k+1][j+i]+p[j]*p[k+1]*p[j+i+1]; if(temp>tmp){ s[j][j+i]=k+1; temp=tmp; } } m[j][j+i]=temp; } } for(int i=0;i<6;i++){ for(int j=0;j<6;j++){ cout.width(5); cout<<m[i][j]<<" "; } cout<<endl; } for(int i=0;i<6;i++){ for(int j=0;j<6;j++){ cout.width(5); cout<<s[i][j]<<" "; } cout<<endl; } PrintOptimal(s,0,5); cout<<endl; }
3. 最长公共子序列问题:
#include <iostream> #include <string> using namespace std; int main(){ string str1,str2,str3; str1="abcbdab"; str2="bdcaba"; str3=""; int m[8][7]={0}; pair<int,int> s[8][7]={make_pair(0,0)}; for(int i=1;i<8;i++){ for(int j=1;j<7;j++){ if(str1[i-1]==str2[j-1]){ m[i][j]=m[i-1][j-1]+1; s[i][j]=make_pair(-1,-1); } else{ if(m[i-1][j]<m[i][j-1]){ m[i][j]=m[i][j-1]; s[i][j]=make_pair(0,-1); } else { m[i][j]=m[i-1][j]; s[i][j]=make_pair(-1,0); } } } } for(int i=0;i<8;i++){ for(int j=0;j<7;j++){ cout<<m[i][j]<<" "; } cout<<endl; } for(int i=0;i<8;i++){ for(int j=0;j<7;j++){ cout.width(2); cout<<s[i][j].first; cout<<","; cout.width(2); cout<<s[i][j].second<<" "; } cout<<endl; } cout<<"The longest common string length is "<<m[7][6]<<endl; for(int i=7,j=6;i>0&&j>0;){ if(s[i][j].first==-1&&s[i][j].second==-1){ str3=str1[i-1]+str3; } int temp=s[i][j].second; i+=s[i][j].first; j+=temp; } cout<<"The longest common sring is "<<str3<<endl; }
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C++的template模板中class与typename关键字的区别分析
- C与C++之间相互调用实例方法讲解