多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,创立了解决这类过程优化问题的新方法——动态规划 个人的理解:就是处于当前决策时要依赖前面的已知情况,将看似”连续无统一标准解决方案“的问题分割成多个”可以商量的“的决策过程。(商量就是依靠已知的情况觉得未知) 那么什么问题才可以用到动态规划呢?看问题的性质。
1. 最优子结构: 就是多步决策中的子问题的最优解也是最终问题的最优解。 2. 重叠子问题: 就是每次在求解子问题的过程中,总存在一些之前已经求出来的子问题了。 3. 无后效性: 就是当前决策只依赖于之前已经解决的结果,只对过去的历史进行总结,并不影响未来(最近看时空穿梭看多了 - _ -|| )。
此处结合经典例题进行分析: http://acm.nyist.net/JudgeOnline/problem.php?pid=737 (石子归并问题) 1.找出最优解的性质刻画其结构特征。 本质上就是找一张表来表示你要解决的问题,这个表的性质是怎么样的。就要依据问题最优解的结构和状态来决定:(比如这个问题要求的最优解就是1~n堆石头合并的最小代价。就可以求二维表中dp[1][n]的最小值,简单的描述就是min(dp[1][n])) 2. 递归的定义出最优值。 换而言之就是找让dp[1][n]尽可能小的递推关系式,这取决于我们如何做决策,很明显就是通过分割每个部分来进行比较哪种分割方式代价最小来决定。那麽自然而然就可以假设dp[i][j]=min(dp[i][k]+dp[k+1][j]+i~j的代价)。这样就得到了递推关系式,这也是dp问题的难点。 3. 以自底向上的方式求出最优解。 很显然要到初始最小值才能得到最终最小值。只有从已知推未知,所以就要从一堆的不能分割到2堆.3堆…n堆。 AC代码:
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; const int INF = 1 << 30; const int N = 205; int dp[N][N]; int sum[N]; int a[N]; int main() { int n; while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) scanf("%d",&a[i]); sum[1] = a[1]; for(int i=2;i<=n;i++) sum[i] = sum[i-1] + a[i]; //代价数组; for(int i=1;i<=n;i++) dp[i][i] = 0; //初始只有一堆的情况; for(int v=2;v<=n;v++) { for(int i=1;i<=n-v+1;i++) { int j = i + v-1; dp[i][j] = INF; int tmp = sum[j] - (i > 1 ? sum[i-1]:0); for(int k=i;k<j;k++) dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j] + tmp); } } printf("%d\n",dp[1][n]); } return 0; }这个石子归并问题虽然简单但是它充分的体现了动态规划的所有性质,是一个很经典的题目,可以多做一些拓展例如不是一列石头堆,而是一个环形的。 例题分享:http://blog.csdn.net/txl199106/article/details/40620957