HDU3535:分组背包

本文详细解析了HDU3535题目的分组背包问题,通过定义dp数组来求解不同约束条件下的最大价值,包括至少选一个、至多选一个及随便选的情况,并提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HDU3535

题解:分组背包问题好题目。

定义dp[i][j]为考虑到第i组,背包容量为j时的最大价值 

  1. s == 0,至少选一个。那么dp[i]初始化为-inf。dp[i][k]要从dp[i][k-weight]+val和dp[i-1][k-weight]+val转移过来。所以      dp[i][k] = max(dp[i][k],max(dp[i][k-weight]+val,dp[i-1][k-weight]+val))。仔细想想,因为初始化为-inf,所以第一次从dp[i-1]转移过来一定选中了第i组的一件物品。 
  2. s == 1,至多选一个。这就变成了普通的01背包问题。从上一个状态转移过来。
  3. s == 2,随便选。这类似于完全背包问题。

代码:

#include <bits/stdc++.h>
using namespace std;
int const inf = 0x3f3f3f3f;
int const N = 100 + 10;
int n,m,s,T,weight,val;
int dp[N][N];    //dp[i][j]表示考虑到第i组,容量为j的最大价值
int main(){
	while(~scanf("%d%d",&n,&T)){    //剩余T的时间
		memset(dp,0,sizeof(dp));
		for(int i=1;i<=n;i++){   //共有n组
			scanf("%d%d",&m,&s);   //每组有m个任务,类型为s;
			if(s == 0){    //但是至少得有一个工作,带限制的完全背包问题
				for(int j=0;j<=T;j++)	dp[i][j] = -inf;   //初始化负无穷,从后面的状态转移过来,保证选一个
				for(int j=1;j<=m;j++){
					scanf("%d%d",&weight,&val);
					for(int k=T;k>=weight;k--)     //逆序,每一组可选择多个,但是每一个之多选一个
						dp[i][k] = max(dp[i][k],max(dp[i][k-weight]+val,dp[i-1][k-weight]+val));
				}
			}
			else if(s == 1){    //普通01背包问题,最多选一个,从上一个状态转移
				for(int j=0;j<=T;j++)	dp[i][j] = dp[i-1][j];
				for(int j=1;j<=m;j++){
					scanf("%d%d",&weight,&val);
					for(int k=T;k>=weight;k--)   //可正或逆
						dp[i][k] = max(dp[i][k],dp[i-1][k-weight]+val);
				}
			}
			else{    //01背包背包,无限制选择,从上一个状态转移,
				for(int j=0;j<=T;j++)	dp[i][j] = dp[i-1][j];
				for(int j=1;j<=m;j++){
					scanf("%d%d",&weight,&val);
					for(int k=T;k>=weight;k--)   //逆序,总共有m件物品,对于每一件物品,最多选一个
						dp[i][k] = max(dp[i][k],dp[i][k-weight]+val);  //在目前的状态上转移
				}
			}
		}
		printf("%d\n",dp[n][T] < 0 ? -1:dp[n][T]);
	}
	return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值