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;
 }
posted @ 2020-07-14 20:24  神奇周一  阅读(100)  评论(0)    收藏  举报