动态规划的定义
要解决一个复杂的问题,可以考虑先解决其子问题。这便是典型的递归思想,比如最著名的斐波那契数列,讲递归必举的例子。
斐波纳契数列的定义如下:F(0)=1,F(1)=1, F(n)=F(n-1)+F(n-2)(n>=2,n∈N*)
用递归可以很快写出这样一个函数,咋一看真牛逼,几行代码就搞定了
int fib(int i)
{
if(i <= 1)
{
return 0;
}
return fib(i - 1) + fib(i - 2);
}
将该函数的执行过程用图表示出来,就会发现fib4执行了一次,fib3执行了两次,fib2执行了三次,fib1计算了5次,重复的次数呈现爆发增长,接近与指数级。如果n取得足够大,暂且不说费时的问题,直接就会因为递归次数太多,函数堆栈溢出而程序奔溃。
那么很快就有人想到,用一个数组来保存曾经计算过的数据来避免重复计算。这种思想便是动态规划!
我们来实现一下
#include <iostream>
#include <stdlib.h>
#include <vector>
using namespace std;
int fib(int n, vector<int>& vec);
int main(int argc, char** argv)
{
if(argc != 2)
{
cout << "usage: ./a.out number" << endl;
}
int num = atoi(argv[1]);
vector<int> vec(num + 1, -1);
int ret = fib(num, vec);
cout << "fib(" << argv[1] << ")" << " = " << ret << endl;
return 0;
}
int fib(int n, vector<int>& vec)
{
if(n <= 1)
{
return 1;
}
if(vec[n] == -1)
{
vec[n] = fib(n - 1, vec) + fib(n - 2, vec);
}
return vec[n];
}
当然,对于递归问题也可以转化为循环来解决。
#include <iostream>
#include <stdlib.h>
using namespace std;
int fib(int n);
int main(int argc, char** argv)
{
if(argc != 2)
{
cout << "usage: ./a.out number" << endl;
}
int ret = f