算法分析与设计(四)动态规划(二)
来源:互联网 发布:站桩 知乎 编辑:程序博客网 时间:2024/05/23 05:08
动态规划的概念复习
每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划。
动态规划的思想和策略
将待求解的问题分解为若干个子问题,按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。
适合用动态规划求解的问题,经分解后得到的子问题往往不是互相独立的。(这一点与分治法不同)
能用动态规划求解的问题一般具有三个性质
1.最优化原理(最优子结构性质)
2.无后效性(当前状态一旦确定,就不受以后状态决策的影响)
3.有重叠子问题(子问题不相互独立,因而当前子问题的解可以为以后子问题的解提供参考)
动态规划求解的基本步骤
1.划分阶段
2.确定状态和状态变量
3.确定决策并写出状态转移方程
4.寻找边界条件
例题深入
1.字符串解码
问题描述:一个包含字母的消息被加密后变成了只包含数字的字符串,我们现在知道加密的规则:A–>1 ; B–>2 …… Z–>26 ;
现在给定一个已经被加密的只包含数字的字符串,求出该字符串有多少种被解密的方法。例如 “12” -> AB 或者 “12”->L 。
分析:假设定义一个数组,dp[i]为到第i个数字所能够组成的所有解码方式的个数,那么对于dp[i+1]来说,如果第i个数字和第i+1个数字不能构成一个字符的编码,那么第i+1个数字单独解码,解码方式的个数和有i个数字是相同的,即 dp[i+1] = dp[i] ;反之,如果第i个数字和第i+1个数字能构成一个字符的编码,那么解码方式的个数就等于前i-1个数字的解码方式个数加上前i个数字的解码方式的个数,即dp[i+1] = dp[i] + dp[i-1],因为此时你可以选择第i+1个数字单独解码,那么方法数等于dp[i],或者第i个和第i+1个一起编码,方法数等于dp[i-1]。
代码实现
#include<iostream>#include<string>#include<vector>using namespace std;/*** 求解字符串的解码方法总数* @param str 需要解码的字符串* @return int 解码方法的总数*/int Decod_num(string& str){ //定义一个数组记录解码方式的个数 vector<int> vec( str.size() , 1 ); //只有一个数字,解码方式就一种 if( str.size() < 2 ){ return 1 ; } //26以内的数字,解码方式两种 if( str[0] == '1' || (str[0] == '2' && str[1] <= '6')){ vec[1] = 2 ; } int i ; int tmp ; //动态规划求解过程 for( i = 2 ; i < str.size() ; i ++ ){ //判断是合法的字符 if( str[i] >= '0' && str[i] <= '9'){ //状态转移1,i个数字的解码方法数至少是前i-1个数字的解码方法数 vec[i] = vec[i-1]; }else{ return 0 ; } tmp = str[i-1] - '0'; tmp = tmp*10 + str[i]-'0'; //判断最后两个数字是否能构成一个字符的编码 if( str[i-1] != '0' && tmp <= 26){ //状态转移2, i个数字的解码方法数等于前i-1个数字的解码方法数加上前i-2个数字的解码方法数 vec[i] += vec[i-2]; } } //数组的最后一位即当前字符串的解码方法总数 return vec[str.size()-1];}
2.矩阵最小路径和
问题:给定一个二维矩阵,矩阵的每个元素指定了走到该出所需要的代价,要你从矩阵左上角到右下角,寻找代价最小的一条路径。
分析:到达矩阵的一个点,有两种走法,一是从上面一个格子走过来,一是从左边的格子走过来(边界点除外)。那么,到达一点的最短路径,要么就是到达该点左边一个点的最小代价加上该点的代价,要么就是到达该点上面一个点的最小代价加上该点的代价,两者中的最小值。
即状态转移方程
dp[i][j] = min( dp[i-1][j] + vec[i][j] , dp[i][j-1] + vec[i][j] )
代码实现
/*** 求解矩阵从左上角到右下角的最小路径代价* @param vec 矩阵的二维数组* @return int 最小的路径代价*/int MinPathSum( vector<vector<int>> & vec ){ vector<vector<int>> dp( vec.size() ); int i,j ; //初始化动态规划需要的数组 for( i = 0 ; i < vec.size() ; i ++ ){ dp[i].assign(vec[i].size(),numeric_limits<int>::max()); } dp[0][0] = vec[0][0]; //初始化边界值 for( i = 1 ; i < vec.size() ; i++ ){ dp[i][0] = vec[i][0]+dp[i-1][0]; } for( j = 1 ; j < vec[0].size() ; j++ ){ dp[0][j] = vec[0][j]+dp[0][j-1]; } //求解过程 int temp ; for( i = 1 ; i < vec.size() ; i ++ ){ for( j = 1 ; j < vec[0].size() ; j ++ ){ tmp = min(vec[i][j] + dp[i][j-1] , vec[i][j] + dp[i-1][j]); if( tmp < dp[i][j] ){ dp[i][j] = temp ; } } } return dp[vec.size()-1][vec[0].size()-1];}
3.最大子数组乘积
问题:给定一个整数数组,求解乘积最大的子数组的值
分析:由于数组中可能出现负数,所以当前最大值,可能是之前最大乘以当前值(如果之前最大乘积为正数,且当前数也为正数),也可能是之前最小乘以当前值(如果之前最小乘积为负数,且当前值也为负数,负负得正),也可能是当前数。
所以为了得到全局最优,我们需要两个数组来存储局部最优值,一个保存局部最大值(正数),一个保存局部最小值(负数),并不断更新两个局部最优。
代码实现
/*** 求解最大子数组乘积* @param vec 一维数组* @return int 最大乘积*/int maxProduct( vector<int>& vec){ if( vec.size() == 0 ){ return 0 ; } //一维规划,但是需要两个数组来保存两个局部最优值,以得到全局最大 vector<int> maxcur(vec.size(),0); vector<int> mincur(vec.size(),0); maxcur[0] = vec[0]; mincur[0] = vec[0]; int maxproduct = vec[0]; int i , temp ; for( i = 1 ; i < vec.size() ; i ++ ){ //更新局部最大值 maxcur[i] = max( vec[i] , max(maxcur[i-1]*vec[i],mincur[i-1]*vec[i])); //更新局部最小值 mincur[i] = min( vec[i] , min(mincur[i-1]*vec[i],maxcur[i-1]*vec[i])); //更新全局最大值 maxproduct = max( maxcur[i] , maxproduct ); } return maxproduct ;}
- 算法分析与设计(四)动态规划(二)
- 算法设计与分析(二)动态规划
- 动态规划(算法分析与设计)
- 算法设计与分析(二)之动态规划
- 算法设计与分析(三)动态规划(一)
- 流水作业调度(动态规划)-算法设计与分析
- 算法分析与设计-动态规划0
- 算法分析与设计之五大常用算法 (II)—— 动态规划算法
- 【动态规划(二)】迪杰斯特拉算法与普里姆算法
- 算法设计与分析--01背包问题(动态规划法解决)
- 算法设计与分析--01背包问题(动态规划法解决)
- 算法设计与分析--01背包问题(动态规划法解决)
- 数字三角形问题(简单动态规划)-算法设计与分析
- 基础算法(四)---动态规划算法
- 南邮《算法设计与分析》动态规划源码
- 算法设计与分析复习-动态规划例子代码
- 算法设计与分析之动态规划法
- 算法设计与分析入门篇----动态规划 1
- lintcode1- 1. A + B 问题
- bundle
- 12月14日
- Qt android v-play && 文档
- 算法:插入排序
- 算法分析与设计(四)动态规划(二)
- 动态分配及对动态申请获得的结构体变量进行访问
- caffe利用caffenet运行bvlc_reference_caffenet.caffemodel时错误
- StringBuffer类的常用方法
- SQL中where和having的区别
- 6轴机器人运动学正解,逆解1
- MySQL 事物详解
- java分布式系统部署学习(八)ansible-playbook 简单使用
- php curl请求时,如果有ssl问题时,加下面配置