第三章 动态规划
来源:互联网 发布:tera艾琳捏脸数据 编辑:程序博客网 时间:2024/04/25 05:57
学习要点
理解动态规划的概念
掌握动态规划算法的基本要素
(1) 最优子结构性质
(2) 重复子问题性质
掌握设计动态规划算法的步骤
(1) 找出最优解的性质,并刻画其结构特征
(2) 递归地定义最优值
(3) 以自底向上的方式计算最优解
(4) 根据计算最优值时得到的信息构造最优解。
动态规划与分治法类似,都是将原问题划分成若干子问题求解,不同的是,适用于动态规划法解的问题,经分解得到的子问题往往不是互相独立的。并且,为了避免大量重复计算,可以用一个表来记录所有已解决的子问题的答案,不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划的基本思想。
3.1 矩阵连乘问题
矩阵连乘代码:
void matrixMultiply(int **a,int **b,int **c,int ra,int ca,int rb,int cb){ int i = 0; int j = 0; int k = 0; // 矩阵不可乘 if (ca != rb) return; for (i = 0; i < ra; i++) { for (j = 0; j < cb; j++) { int sum = 0; for (k = 0; k < ca; k++) { sum += a[i][k]*b[k][j]; } c[i][j] = sum; } }}
给定 n 个矩阵 {A1,A2,…,An},其中 Ai 与 Ai+1 是可乘的,i = 1,2,3,…,n-1。考察这 n 个矩阵的连乘积 A1A2,…,An。
由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序。这种计算次序可以用加括号的方式来确定。若一个矩阵连乘积的计算次序完全确定,也就是说该连乘积已完全加括号,则可依次次序反复调用2个矩阵相乘的标准算法计算出矩阵连乘积。完全加括号的矩阵连乘积可以递归的定义为:
(1) 单个矩阵是完全加括号的
(2) 矩阵连乘积A是完全加括号的,则A可表示为2个完全加括号的矩阵连乘积 B和 C的乘积并加括号,即 A = (BC)。
例如: 矩阵连乘积A1A2A3A4 可以有以下 5 种不同的完全加括号方式:
(A1(A2(A3A4)))
(A1((A2A3)A4))
((A1A2)(A3A4))
((A1(A2A3))A4)
(((A1A2)A3)A4)
不同的加括号对应着不同的计算次序,不同的计算次序与计算量有密切的关系。
从以下程序可以得出,矩阵的连乘的计算次数等于 ra*ca*cb。以3个矩阵为例:
{A1,A2,A3} {10*100,100*5,5*50}
((A1A2)A3) 计算次数:10*100*5+10*5*50 = 5000+2500 = 7500
(A1(A2A3)) 计算次数:100*5*50+10*100*50 = 25000+50000 = 75000
可见运算次序是多么重要,于是我们需要寻找最优的运算次序使得乘次数最少。
那么如何让矩阵的连乘次数最少呢?
m[i][j] 数组
j
i 1 2 3 4 5 6
1 0
2 0
3 0
4 0
5 0
6 0
由于 i < j 因此求取问号区域的值
j
i 1 2 3 4 5 6
1 0 ? ? ? ? ?
2 0 ? ? ? ?
3 0 ? ? ?
4 0 ? ?
5 0 ?
6 0
m[i][j] = min{m[i][k]+m[k+1][j]+(pi-1*pk*pj)} i < j,i <= k < j
j
i 1 2 3 4 5 6
1 0 k ? ? ? ?
2 0 k ? ? ?
3 0 ? ? ?
4 0 ? ?
5 0 ?
6 0
以 m[1][3]为例,依次需要的数据有 m[1][1],m[2][3],m[1][2],m[3][3],看出来需要首先计算列以下内容,然后依次计算。
同理,求取 m[1][4],需要提前知道 m[1][1],m[2][4],m[1][2],m[3][4],m[1][3],m[4][4].
j
i 1 2 3 4 5 6
1 0 k k ? ? ?
2 0 k k ? ?
3 0 k ? ?
4 0 ? ?
5 0 ?
6 0
由此得到循环的Code
#include <stdio.h>#include <string.h>#include <stdlib.h>void MatrixChain(int *p,int n,int **m,int **s);int main(){ int i = 0; int n = 0; /* 矩阵维度的数组 N+1 */ int *p = NULL; /* 矩阵最少乘法次数的数组 (N+1)*(N+1) */ int **m = NULL; /* 矩阵拐弯的记录数组(N+1)*(N+1) */ int **s = NULL; scanf("%d",&n); p = (int *)malloc((n+1)*sizeof(int)); m = (int **)malloc((n+1)*sizeof(int*)); s = (int **)malloc((n+1)*sizeof(int*)); for (i = 0; i < n+1; i++) { *(m+i) = (int *)malloc((n+1)*sizeof(int)); *(s+i) = (int *)malloc((n+1)*sizeof(int)); scanf("%d",&(p[i])); } /* 计算矩阵相乘次数*/ MatrixChain(p,n,m,s); free(p); free(m); free(s); return 0;}void MatrixChain(int *p,int n,int **m,int **s){ int i = 0; int j = 0; int k = 0; for (i = 0; i <= n; i++) { m[i][i] = 0; } for (j = 1; j <= n; j++) { for (i = j-1; i > 0; i--) { m[i][j] = m[i+1][j]+p[i-1]*p[i]*p[j]; s[i][j] = i; for (k = i+1; k < j; k++) { if (m[i][j] > m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j]) { m[i][j] = m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j]; s[i][j] = k; } } } } printf("m[1][n] = %d",m[1][n]);}
- 第三章 动态规划
- 动态规划详解 第三章
- [NOIP复习]第三章:动态规划
- leetcode动态规划第三期
- 第三专题总结(动态规划)
- ACM第三专题—动态规划总结
- 第三章 规划
- 算法导论 第三版 动态规划之库存规划
- [NOIP 2014复习]第三章:动态规划——NOIP历届真题回顾
- 第十五章 动态规划
- 第十五章 动态规划
- 动态规划第三讲——序列化的动态规划问题
- 动态规划第三讲——序列化的动态规划问题
- 【141106noip训练】动态规划第三题:尼克的任务
- 算法导论(第三版)-复习15动态规划
- 动态规划-----两个字符串交叉组成第三个字符
- 动态规划!!!动态规划!!!
- 动态规划详解 第二章
- js中屏蔽a标签右键中在新窗口打开功能
- Zxing的使用
- Linux内存分配函数5
- 对hive和hbase的理解 基于【浅谈Hive vs. HBase】
- django设置当浏览器关闭时,session失效
- 第三章 动态规划
- 燃气灶点火好不好该怎么解决
- [问题记录]解决警告"ld: warning: directory not found for option XXXX"
- 【C/C++学院】0805-语音识别控制QQ/语音控制游戏
- 在eclipse中修改svn的用户名和密码
- ZOJ 1091 Knight Moves
- 直接路由模式(LVS-DR)
- 海量数据处理算法—Bloom Filter
- 查看Linux内核版本的命令