AreYouBusy HDU - 3535 (混合背包)

题意:
有n个集合,每个集合中有m个元素。求在背包容量为T的情况下,取得元素的总“价值”最大。
这些集合又分为3种类型(用于限制取元素):
0.在这个集合中,至少取一个元素。
1.在这个集合中,最多取一个元素。
2.在这个集合中,可以任意数量的元素。

题解:
混合背包。
对于不同的集合(限制),用不同的方法(主要差别在怎么处理上次得到的最优解)。
对于类型 1 的集合。上次的最优解是不能更改的。

代码:

#pragma GCC optimize(2,"Ofast","inline")
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<vector>
#include<cstring>
#include<queue>
#include<stack>
#include<list>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
#include<cstdlib>
#include<bitset>
#include<functional>
#include<ctime>
#define F(i,s,t) for(int i=(s);i<=(t);i++)
#define D(i,s,t) for(int i=(s);i>=(t);i--)
#define dBug(i) printf("Value=%d\n",i)
#define ddBug(i,j) printf("Value=%d %d\n",i,j)
#define ed putchar('\n')
#define FO freopen("D:\\in.txt","r",stdin)
#define IOS cin.tie(0) ,cout.tie(0), cout.sync_with_stdio(0)
typedef long long ll;
const int INF = 1 << 30;
//const double EPS = 1e-6;
//#define MX 1002
//#define Mod 10000
using namespace std;

struct Job
{
	int c, g;
};
Job J[110];
int dp[110][110];
int n, T;//第一行输入的值,n表示number of sets,T表示现有的时间
int m, s;//m表示number of jobs,s表示type of jobs

int main()
{
	IOS;
	//FO;
	while (scanf("%d %d", &n, &T) != EOF){
		F(i, 1, n){//有n种工作
			scanf("%d %d", &m, &s);
			F(j, 1, m)//第i种工作有m个
				scanf("%d %d", &J[j].c, &J[j].g);


			if (s == 0){//choose at least 1
				F(k, 0, T)//取至少一种
					dp[i][k] = -INF;

				//下面是01背包了
				F(j, 1, m)//遍历物品
					D(k, T, J[j].c)//背包容量
					//把dp[i][k]赋值为无穷小,所以一定会更dp[i-1][k]的哈(因为它的价值和大)。
					dp[i][k] = max(dp[i][k], max(dp[i][k - J[j].c], dp[i - 1][k - J[j].c]) + J[j].g);
			}//if (s == 0)

			else if (s == 1){//choose at most 1
				F(k, 0, T)
					dp[i][k] = dp[i - 1][k];

				F(j, 1, m)
					D(k, T, J[j].c)
					//每次dp[i][k]是否更新取决于dp[i-1][k],而dp[i-1][k]又是不会改变的
					dp[i][k] = max(dp[i][k], dp[i - 1][k - J[j].c] + J[j].g);
			}//else if (s == 1){

			else{
				F(k, 0, T)
					dp[i][k] = dp[i - 1][k];
				//下面是01背包了

				F(j, 1, m)
					D(k, T, J[j].c)
					dp[i][k] = max(dp[i][k], dp[i][k - J[j].c] + J[j].g);

			}//else
		}//extren for
		if (dp[n][T] > 0)
			printf("%d\n", dp[n][T]);
		else
			printf("-1\n");
	}//while
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值