2.3记录结果再利用的动态规划
动态规划
记忆化搜索与动态规划(背包问题)
有n个重量和价值分别为wi,vi的物品,从这些中挑选总重量不超过W的物品,求所选方案中价值总和最大值
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e2+5 ;
int w[maxn],v[maxn];
int n,W ;
int rec(int i,int j)
{
int ans;
if(i==n) ans=0;//无剩余用品
else if(j<w[i])ans=rec(i+1,j);//不能选取
else{ans=max(rec(i+1,j),rec(i+1,j-w[i])+v[i]);}//评判选与不选那个更划算
return ans;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
cin>>w[i]>>v[i];
cin>>W ;
printf("%d\n",rec(0,W ));
}
可以看到的是,此方法使得每一层搜索都有两次分支,使得时间复杂度达到了O(2^n)。但在此递归中会出现较多的重复调用,这也是我们简化、加快计算时间的突破口——将第一次计算的结果都记录下来,这样就能避免多次计算。
这种方法也叫记忆化搜索。只有在第一次被调用时执行递归部分,将复杂度缩减到了O(nW)
int dp[maxn+1][maxn+1];
int rec(int i,int j)
{
if(dp[i][j]>=0) return dp[i][j];//用dp数组进行存储
int ans;
if(i==n) ans=0;
else if(j<w[i])ans=rec(i+1,j);
else{ans=max(rec(i+1,j),rec(i+1,j-w[i])+v[i]);}
return dp[i][j]=ans;
}
memset数组初始化
按照1字节为单位对内存进行填充(不能初始化为1之类的数值!!!)
memset(dp,-1,sizeof(dp));//-1√ 0√ inf√ -inf√
又因为可以写出递推式:
dp[n][j]=0
dp[i][j]={max(dp[i+1][j],dp[i+1][j]-w[i])+v[i]) //其他
{dp[i+1][j] //j<W[i]
所以也可以直接写作一个二重循环。
int DP[maxn+1][maxn+1];
void solve ()
{
/*for(int j=0;j<=W ;j++)
DP[n][j]=0;*/ //全局数组会被初始化为0
for(int i=n-1;i>=0;i--)
for(int j=0;j<=W ;j++)
{
if(j<w[i]) DP[i][j]=DP[i+1][j];
else DP[i][j]=max(DP[i+1][j],DP[i+1][j]-w[i])+v[i]);
}
cout<<DP[0][W ]<<endl;
}

浙公网安备 33010602011771号