动态规划

mac2025-07-29  8

基本思想

将待求解的问题分解成若干子问题,先求子问题,然后从子问题的解得到原问题的解。适用于动态规划法求解的问题,经分解得到的子问题往往不是相互独立的。保存已解决子问题的答案,在需要时再找出已求得的答案,这样就可以避免大量的重复计算用一个表来记录所有已解决的子问题的答案,不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。

步骤

找出最优解的性质,并刻画其结构特征递归地定义最优值以自底向上地方式计算最优值根据计算最优值时得到地信息,构造最优解

例题

矩阵连乘问题

#include<iostream> using namespace std; // 假设要计算地矩阵连乘的行列为 (30,35) (35,15) (15,5) (5,10) (10,20) (20,25) int p[7] = {30, 35, 15, 5, 10, 20, 25}; int m[6][6]; // m[i][j] = x 表示第i个矩阵到第j个矩阵之间连乘的最小数乘次数为x int s[6][6]; // s[i][j] = x表示断开位置x可以得到最小数乘次数 // 计算最优值 void MatrixChain(int *p, int n, int m[6][6], int s[6][6]) { for(int i=1; i<=n; i++) m[i][i] = 0; // 单一矩阵数乘次数置为0 for(int r=2; r<=n; r++){ // 控制矩阵i到矩阵j的间隔 for(int i=1; i<=n-r+1; i++){ int j = i+r-1; // 初始化断开位置为i m[i][j] = m[i+1][j] + p[i-1]*p[i]*p[j]; s[i][j] = i; // 寻找断开位置K,使得连乘次数最小 for(int k=i+1; k<j; k++){ int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j]; if(t < m[i][j]){ m[i][j] = t; s[i][j] = k; } } } } } // 构造最优解 // 根据构造的最佳断点矩阵s输出最佳计算次序 void Traceback(int i, int j, int s[6][6]) { if(i == j) return ; Traceback(i, s[i][j], s); Traceback(s[i][j]+1, j, s); cout << "MultipyA" << i << "," << s[i][j]; cout << "and A" << s[i][j]+1 << "," << j << endl; } int main() { MatrixChain(p, 6, m, s); Traceback(2, 5, s); return 0; }

最长公共子序列

#include<iostream> using namespace std; char x[] = "asdfghjk", y[] = "dfgrtufss"; int c[100][100]; // c[i][j] = s表示x中前i个元素和y中前j个元素的公共子序列长度为s // 那么x,y的最长公共子序列就为c[m][n] int b[100][100]; // 保存c[i][j]是由那种情况组成的 // 计算最优值 void LCSLength(int m, int n, char *x, char *y, int c[][100], int b[][100]) { for(int i=1; i<=m; i++) c[i][0] = 0; for(int i=1; i<=n; i++) c[0][i] = 0; for(int i=1; i<=m; i++) { // 当x序列只有前i个元素 for(int j=1; j<=n; j++){ // 当y序列只有前j个元素 //当两个序列的最后一个元素相同时,都除去最后一个元素, //判断前面元素的最长子序列,结果加1即可 if(x[i] == y[j]){ c[i][j] = c[i-1][j-1] + 1; b[i][j] = 1; //情况1 } // 当两个序列的最后一个元素不同时,如果x序列除去最后一个元素与序列y的最长公共子序列 // 相比较于y序列除去最后一个元素与序列x的最长公共子序列,前者不小的情况下 // 选择前者的公共子序列长度作为结果 else if(c[i-1][j] >= c[i][j-1]){ c[i][j] = c[i-1][j]; b[i][j] = 2; // 情况2 } // 后者大的情况 else{ c[i][j] = c[i][j-1]; b[i][j] = 3; // 情况3 } } } } // 构造最长公共子序列 void LCS(int i, int j, char *x, int b[][100]) { if(i==0 || j ==0) return; if(b[i][j] == 1){ LCS(i-1, j-1, x, b); cout << x[i]; } else if(b[i][j] == 2) LCS(i-1, j, x, b); else LCS(i, j-1, x, b); } int main() { LCSLength(8, 9, x, y, c, b); LCS(8, 9, x, b); return 0; }
最新回复(0)