动态规划:与分治法类似,也是将大规模的问题分解为若干个子问题,先求解子问题,再从这些子问题的解得到原问题的解。但是动态规划解决的这些问题,他们经分解后的子问题往往是互相不独立的。这时候,再用分治法解决就会耗费大量的时间。且在这过程中,会有一些子问题被我们进行重复求解,很不划算。
因此,出现动态规划思想:如果将已经解决的子问题的解保存到一张表中,不管该子问题以后是否被用到,只要他被计算过,就将其结果填入表中。
动态规划算法步骤:
- 找出最优子结构性质,并刻画其结构特征
- 递归的定义最优值
- 以自底向上的方式计算出最优值
- 构造最优解
浅试一下: 最长公共子序列问题:
给定两个序列X =
dp[m][n]则存储两个字符串的最长公共子序列长度
写出动态规划的最优解计算公式:
具体实现:
templatevoid Print_Vec(vector >& c) { int m = c.size(); for (int i = 0; i < m; ++i) { int n = c[i].size(); for (int j = 0; j < n; ++j) { cout << setw(3) << c[i][j]; } cout << endl; } cout << endl; } int LCSLength(const char* X, const char* Y, int m, int n, vector >& c, vector >& s) { if (m == 0 || n == 0) return 0; else if (c[m][n] != 0) return c[m][n]; else { if (X[m] == Y[n]) { c[m][n] = LCSLength(X, Y, m - 1, n - 1, c, s) + 1; s[m][n] = 1; } else { int max1 = LCSLength(X, Y, m - 1, n, c, s); int max2 = LCSLength(X, Y, m, n - 1, c, s); if (max1 > max2) { c[m][n] = max1; s[m][n] = 2; } else { c[m][n] = max2; s[m][n] = 3; } } } return c[m][n]; } int LCS(string& X, string& Y,vector >&c, vector >& s) { int n = X.size() - 1; int m = Y.size() - 1; for (int i = 0; i <= n; ++i) c[i][0] = 0; for (int j = 0; j <= m; ++j) c[0][j] = 0; for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { if (X[j] == Y[i]) { c[i][j] = c[i - 1][j - 1] + 1; s[i][j] = 1; } else { //c[i][j] = max(c[i - 1][j], c[i][i - 1]); if (c[i - 1][j] > c[i][j - 1]) { c[i][j] = c[i - 1][j]; s[i][j] = 2; } else { c[i][j] = c[i][j - 1]; s[i][j] = 3; } } } } return c[n][m]; } int main() { string X= { "#ABCBDAB" }; string Y= { "#BDCABA" }; int xm = X.size()- 1, yn = Y.size() - 1; vector > c, s; c.resize(xm + 1); s.resize(xm + 1); for (int i = 0; i < xm + 1; ++i) { c[i].resize(yn + 1, 0); s[i].resize(yn + 1, 0); } int maxlen = LCS(X, Y, c, s); cout << maxlen << endl; Print_Vec(c); Print_Vec(s); return 0; }
打印出中间动态规划的表,方便理解算法的走向
算法练习:
写出最优解计算公式:
具体实现:
//打家劫舍:相邻不能偷 int Rob(vector总结& values, int* dp) { int n = values.size(); if (n == 0) return 0; for (int i = 1; i < n; ++i) { if (i == 1) { dp[i] = values[i]; } else if (i == 2) { dp[i] = values[1] > values[2] ? values[1] : values[2]; } else { dp[i] = std::max(dp[i - 1], dp[i - 2] + values[i]); } } return dp[n]; } int main() { vector nums = { 0,1,2,3,1 };//0下标不存,方便计算 int n = nums.size(); int* dp = new int[n+1]; cout << Rob(nums,dp); delete []dp; return 0; }
主要是,在不同的情况之下,写出符合当前情况的最优解的计算公式,就可以很好的编程了。



