您的位置:首页 > 编程语言 > C语言/C++

动态规划算法总结及实例简介

2016-06-24 19:48 225 查看
动态规划特点:

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++ 动态规划