背包问题模板

01背包问题(给定某种物品)

for(int i=n;i>=1;i--){    //dp[i][j]表示处于从第i个阶段到最后一个阶段的最大花费
    for(int j=0;j<=m;j++){    //必须遍历所有的状态
            if(j<=weight[i])  dp[i][j] = dp[i+1][j];
            else dp[i][j] = max(dp[i+1][j],dp[i+1][j-weight[i]]+val[i]);
	}
}
for(int i=1;i<=n;i++){        //表示取了第i件物品的最大价值
    for(int j=weight[i];j<=m;j++){    //必须遍历所有的状态
            if(j<=weight[i])  dp[i][j] = dp[i-1][j];
	    else dp[i][j] = max(dp[i][j],dp[i-1][j-weight[i]]+val[i]);
	}
}

滚动数组:

  • 如果题目求背包必须装满情况下的最大值,那么dp[0] = 0,其余为-inf。因为背包可以在什么都不装的情况下达到最大值0。而在其它容量下,还是未知的。如果最后dp[V] = -inf,则表明不存在这样的容量V被恰好装满。
  • 如果题目求不用全部装满情况下的最大值,那么dp[0…n] = 0。因为存在合法情况就是什么都不转,其价值为0。
for(int i=1;i<=n;i--){    //滚动数组,不用转移状态
	for(int j=m;j>=weight[i];j--)
		dp[j] = max(d1[j],dp1[j-weight[i]]+val[i]);	}

完全背包问题(物品无穷多)

    for (int i = 1; i <= n; i++) {
        for (int j = weight[i]; j <= m; j++) {   //注意顺序,利用当前的状态
            f[j] = max(f[j], f[j - weight[i]] + value[i]);
        }
    }

优化:

  • 将价值小的而体积大的去掉。

  • 将体积大于容量的去掉。

多重背包问题(限定物品的数量)

转换为01背包问题

	for(int i=1;i<=n;i++){
		int v,w,num;
		scanf("%d%d%d",&v,&w,&num);
		while(num--)	val[++tot] = v,	weight[tot] = w;
	}

二进制优化

	for(int i=1;i<=n;i++){
		int v,w,num;
		scanf("%d%d%d",&v,&w,&num);
                int c = 1;
		while(num > c){
                    val[++tot] = c*v,	weight[tot] = c*w;
                    num -= c;
                    c *= 2;
                }
                val[++tot] = num*v,  weight[tot] = num*w;
        }

单调队列优化

stl版本

	for(int i=1;i<=n;i++){
		scanf("%d%d%d",&weight,&val,&num);
		for(int a=0;a<weight;a++){   //枚举余数  
			qv.clear(),qn.clear();				//前者维护最大值,后组维护对应的数量
			for(int k=0;a+k*weight<=v;k++){ 
				int tmp = dp[a+k*weight] - k*val;
				if(!qv.empty() && qn.front()+num+1==k)	qv.pop_front(),	qn.pop_front();
				while(!qv.empty() && qv.back()<=tmp)	qv.pop_back(),qn.pop_back();
				qv.push_back(tmp);
				qn.push_back(k);
				dp[a+k*weight] = qv.front() + k*val;
			}
		}
	}

数组模拟版本

        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&weight,&val,&num);
            for(int a=0;a<weight;a++){   //枚举余数  
              	int head = 0,body = 0;
              	for(int k=0;a+k*weight<=v;k++){
              		int tmp = dp[a+k*weight] - k*val;
              		if(qn[head] + num + 1 == k)	head++;
              		while(head < body && qv[body-1] <= tmp)	body--;
              		qn[body] = k;
              		qv[body++] = tmp;
              		dp[k*weight+a] = qv[head] + k*val;
              	}
            }
        }

二维费用背包问题

POJ2576 && HDU2159

for(int i=1;i<=n;i++){
	scanf("%d%d%d%d",&v,&u,&val);    //v表示费用1,u表示费用2
	for(int j=s1;j>=v;j--){    //s1,s2分别表示限制容量
		for(int k=s2;k>=u;k--){
			dp[j][k] = max(dp[j][k],dp[j-v][k-s2]+val);
		}
	}
}
int ans = 0;   //求最大价值,注意最后结果不是dp[s1][s2]  ??
for(int i=0;i<=s1;i++){    
	for(int j=0;j<=s2;j++){
		ans = max(ans,dp[i][j]);
	}
}
比如背包容量为12
物品1  价值10,体积12  所以dp[12][1] = 10
物品2  价值20,体积8,	  所以dp[8][1] = 20

分组背包问题

HDU3535

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值