动态规划算法的一个特点就是通过记忆(memomorization), 记录下原问题的子问题的最优解(因为原始问题具有最优子结构), 从而 来避免通过递归, 重复的计算子问题。
下面, 我们首先假设我们关于不同长度的木头的价格表, 如下:
然后, 我们的目的就是通过选择切割方案使得我们的收益达到最大。
首先我们看看如何采用递归的方式解决这个问题。 一个recursive functio完全可以通过数学式子表示。
然后, 我们将我们的recursive version 通过引入memorization 来避免recursive, 即是我们的动态规划算法(dynamic programming)。递归程序如下:
#include <iostream>
#include <vector>
using namespace std;
double recurRodCutting(const vector<double>&p, int n) {
if (n < 1) return 0.0;
double Max = p[n]; //if donot cut off
for (int i = 1; i < n; i++) {
double temp = p[i] + recurRodCutting(p, n - i);
if (temp > Max) Max = temp;
}
return Max;
}
int main()
{
vector<double> prices = {1, 3, 3, 5, 5, 7, 8, 3, 10, 10};
cout << recurRodCutting(prices, 10) << endl;
return 0;
}
运行结果如下, 有问题的:
显然是有问题的,太大了, 那么问题出在哪里呢???
需要调试, 我们可以通过在程序中埋进去一些cout<< 以在输出查看结果, 或者我们也可以直接通过设置断点debug。
最终, 我们发现错误忘记了将第一个假如0 放在vector 的第一个元素了。 因为vector 的indice 是从0 开始的:
#include <iostream>
#include <vector>
using namespace std;
double recurRodCutting(const vector<double>&p, int n) {
if (n < 1) return 0.0; // base case
// cout << n << endl;
double Max = p[n]; //if do not cut off
for (int i = 1; i < n; i++) {
double temp = p[i] + recurRodCutting(p, n - i);
// cout << i << " " << temp << endl;
if (temp > Max) Max = temp;
}
return Max;
}
int main()
{
vector<double> prices = {0, 1, 3, 3, 5, 5, 7, 8, 3, 10, 10};
cout << recurRodCutting(prices, 10) << endl;
return 0;
}
运行的结果如下, 这是正确的:
上述的算法是brute force的形式, 时间复杂度达到指数级了。 很不实用。 下面我们使用dynamic programming 修改算法, 使得算法的时间复杂度降为O(n^2), 如下:
#include <iostream>
#include <vector>
using namespace std;
double recurRodCutting(const vector<double>&p, int n) {
if (n < 1) return 0.0; //base case
// cout << n << endl;
double Max = p[n]; //if do not cut off
for (int i = 1; i < n; i++) {
double temp = p[i] + recurRodCutting(p, n - i);
// cout << i << " " << temp << endl;
if (temp > Max) Max = temp;
}
return Max;
}
double dpRodCutting(const vector<double>&p2, int n) {
vector<double> r(n+1);
r[0] = 0.0;
for (int j = 1; j <= n; j++) {
double Max = p2[j];
for (int i = 1; i < j; i++) {
double temp = p2[i] + r[j - i];
if (temp > Max) Max = temp;
}
r[j] = Max;
}
// for (auto x:r) cout << x << " ";
// cout << endl;
return r[n];
}
int main()
{
vector<double> prices = {0, 1, 3, 3, 5, 5, 7, 8, 3, 10, 10};
cout << dpRodCutting(prices, 10) << endl;
return 0;
}
运行结果如下: