01背包状态压缩和记录路径

01背包的状态压缩

 

当然肯定是看了别人的博客,我再重复一下,大神链接:点击打开链接

1、        在看之前希望你已经弄懂了空间复杂度在O(n*w)的算法,空间的压缩到O(w)的状态,其实本质还是一样的,就是从i-1的状态去求解i的状态,在这先看代码:


for(int i=1;i<=n;++i)
{
	for(int j=w;j>=c[i];--j)
		dp[j]=get_max(dp[j],dp[j-c[i]]+p[i]); 
}

2、        代码很是简短,可能你一看到代码就感觉懂了,w的从大到小,那么从小到大可以吗?那是肯定不行的,当w从大到小时,我们每次内层循环求解的是加入i的最优解,那肯定是在i-1的基础上进行的,假如加入i之前dp【j】的每一个值都代表i-1状态的最优解,那么我们加入i时,我们计算的是dp【j】=get_max(dp【j】,dp【j-c【i】】+p【i】);

dp【j-c【i】】+p【i】它的状态肯定是i-1的状态,可以看出j的值按照逆序从大到小求解,每次加入i就需要j-c【i】,这时候j的状态是小的,那肯定是dp【】i-1的状态;

3、        那么如果按照j从小到大的顺序进行求解,当j的值比较大时,j-c【i】是谁的状态,那可就不好说了,可能是已经选择i的状态,也可能是i-1的状态,这样就错了。(我只能解释到这了,好好理解)


路径求解

有没有困惑如何知道选的是哪些呢?说实话别人真的很聪明,zz就好好学吧!

1、        其实问题很简单,我们如何求出的最大值,那么倒退过去不就行了,这里先讲一下二维的情况,一维的后面再说!

2、        我们这里只用了一个公式dp【i】【j】==dp【i-1】【j-i】+p【i】;只要满足这个条件,那肯定是选择了第i个物品,具体看代码

代码如下

int i=n,j=w;
while(i&&j)
{
	if(dp[i][j]==dp[i-1][j-c[i]]+p[i])
	{
		printf("%d %d\n",c[i],p[i]);
		j-=c[i];//进入下一个物品的求解 
	}
	i--; 
}

3、        下面介绍第二方法(这个挺重要的),看代码:

memset(path,0,sizeof(path));
int i,j;
for(i=1;i<=n;++i)
{
	for(j=0;j<=w;++j)
	{
		dp[i][j]=dp[i-1][j]; 
		if(j>=c[i]&&dp[i][j]<dp[i-1][j-c[i]]+p[i])
		{
			dp[i][j]=dp[i-1][j-c[i]]+p[i];
			path[i][j]=1;//用1代表i物品被选中 
		} 
	} 
}

4、        看了第二种方法应该就会一维的如何处理了吧,其实还是用到一个二维数组进行标记一下,然后在循环一下,输出加入的物品



评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值