斐波那契数列问题
#include <iostream>
#include <vector>
#include <algorithm>
#define MAX_N 2147483647
using namespace std;
//斐波那契数列 fib(n)在展开时 同样的n被调用了多次(fib(9)+fib(8) 展开的同时都调用了fib(7)),我们可以利用数列保存的方式优化其递归
int fib(int n)
{
if(n<=1) return n;
return fib(n-1)+fib(n-2);
}
/*优化原理:
*利用记忆法,将斐波那契数列的已经求出的项进行保存到数组中,之后进行递归
* 如果memo[n]这一项的值不等于0,我们可以直接返回,表示该值已经被求出。
* 如果memo[n]等于0,表示该值未被求出,我们就可以利用递归求出该解并存入数组中(作为记忆化保存),之后返回即可。
*/
int memo[MAX_N];
int optimize_fib(int n)
{
if(n<=1) return n;
if(memo[n]!=0) return memo[n];
return memo[n]=optimize_fib(n-1)+optimize_fib(n-2);
}
01背包问题
题目:有n 个重量和价值分别为 wi,vi的物品,从这些物品中挑选总重量不超过 W 的物品,求所有挑选方案中价值总和的最大值。
const vector<pair<int,int>> thingVec{{2,3},{1,2},{3,4},{2,2}};
const int N=4;
const int W=5;
//从第i个物品开始挑选总重小于j的部分
int rec(int i,int j){
int res;
if (i==thingVec.size()){
//已经没有剩余物品了
res=0;
}else if (j < thingVec.at(i).first){
//无法挑选这个物品
res = rec(i+1 , j);
} else{
//挑选和不挑选的两种情况都尝试一下
res = max(rec(i+1,j), rec(i+1 , j - thingVec.at(i).first)+thingVec.at(i).second);
}
return res;
}
//通过记忆化数组,记录function的两个参数,对递归时重复的部分进行了记录和直接返回,降低了时间复杂度
int dp[N+1][W+1];
int rec_DP(int i,int j){
if(dp[i][j] >=0 ) return dp[i][j]; //已经计算过的话直接使用之前的结果
int res;
if(i==N){
res=0;
}else if(j < thingVec.at(i).first){
res = rec(i+1,j);
} else{
res = max(rec(i+1,j),rec(i+1,j)+thingVec.at(i).second);
}
//将结果保存在数组中
return dp[i][j]=res;
}
int main()
{
memset(dp,-1, sizeof(dp));
cout<<rec(0,W);
}
注意: 虽然memset按照1字节为单位对内存进行填充,-1 的每一位二进制位都是 1,
const vector<pair<int,int>> thingVec{{2,3},{1,2},{3,4},{2,2}};
const int N=4;
const int W=5;
int dp[N+1][W+1];
//不写递推公式,简单利用 递推式将各项的值计算出来,使用二重循环也可以解决这一类问题,这便叫做DP。
void solve(){
for (int i = N-1; i>=0; --i) {
for (int j = 0; j <= W; ++j) {
if(j < thingVec.at(i).first){
dp[i][j] = dp[i+1][j];
}else{
dp[i][j] = max(dp[i+1][j],dp[i+1][j-thingVec.at(i).first] + thingVec.at(i).second);
}
}
}
printf("%d\n",dp[0][W]);
}