动态规划-滚动数组

文章介绍了如何使用滚动数组来降低动态规划解背包问题时的空间复杂度,从二维优化到一维。滚动数组分为交替滚动和自我滚动两种方式,其中自我滚动的j循环必须从C到0以避免错误。这种方法能有效地减少存储需求,提高算法效率。
摘要由CSDN通过智能技术生成

        上一次我们分享了动态规划-背包问题的解题方法,最后我们提出了一个疑问,就是如何降低我们的空间复杂度呢?

        用滚动数组可以大大减少使用空间。它能把二维状态方程O(n^2)的空间复杂度优化到一维的O(n),更高维的数组也可以优化后减少一维。

        从上节介绍过的dp转移方程我们不难发现,dp[i][] 只与dp[i-1][] 有关,和前面无关,那些用过的已经多余了,那么干脆就服用这些空间,用新的一行覆盖已经无用的一行(滚动),只需要两行就够了。

        滚动数组分为两种:交替滚动和自我滚动

1. 交替滚动

        我们用now始终指向正在计算的最新一行,old指向已经算过的旧的一行,对照原递推代码,now相当于i,old相当于i-1。

const int N = 1005;
int dp[N][N],w[N],c[N];

int solve(int n,int C){
    int now=0,old=1;
    for(int i=1;i<=n;i++){
        swap(old,now);
        for(int j=1;j<=C;j++){
            if(c[i]>j) dp[now]=dp[old][j];
            else dp[now][j]=max(dp[old][j],dp[old][j-c[i]]+w[i]);
        }
    }
    return dp[now][C];
}

        这里需要我们注意的是,j循环反过来(C~0)也是可以的,但是在下面的自我滚动中,j循环必须是C~0。

2.自我滚动

const int N = 1005;
int dp[N], w[N], c[N];

int solve(int n, int C) {
	for(int i=1;i<=n;i++){
		for(int j=C;j>=c[i];j--){
			dp[j]=max(dp[j],dp[j-c[i]]+w[i]);
		}
	}
	return dp[C];
}

        可以思考以下问什么自我滚动的j循环就必须从C~0?

答:错误的产生是动数组重复使用同一个空间引起的。什么意思呢?加入我们现在要将物品放到我们的dp[5]的这个背包中(假设这个物品放进去合适),那么我就就会对dp[5]进行更新,就设为dp[5]' 吧。现在我们又要将一个价值为3的物品放入我们的dp[8]的这个背包中,那么我们从动态规划方程中不难看出(dp[j]=max(dp[j],dp[j-c[i]]+w[i]);),dp需要用容积是5的背包的相关信息,那么值得我们思考的是,这里用到的信息是dp[5]' ,而不是dp[5],而我们真正需要用到的却是dp[5],这就导致了错误答案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值