分组背包——HDU 3535 AreYouBusy

HDU 3535 AreYouBusy

题目

http://acm.hdu.edu.cn/showproblem.php?pid=3535
学生xiaoA,对于一些职责,她必须至少选择一份工作;但对于某些事情,她最多只能选择一件事;而对于其他,她可以任意选择。一份工作需要时间,并给小小一些幸福点(这意味着她总是愿意做这些工作)。一项工作只能完成一次。需要选择最好的一组给她最大的幸福点工作。
这个题的关键还是在于对三种类型工作的处理。dp的初始化,状态转移公式。

输入输出

输入:
n(组工作)T(总时间)(0 <= n,T <= 100)
m(组中有m个作业) s(类型为s,0代表至少要做1个,1代表应该选择最多1个,2代表可以自由选择)(0 <m <= 100)
ci(第i个工作ci分钟完成) gi(完成第i个工作可以获得gi幸福点)(0 <= ci,gi <= 100)
多组数据,每组数据以两个整数n和T开始。

输出:
最大幸福点。如果无法完成至少要完成的,输出-1。
多组数据。

思路

分组背包,外层循环组数。内层针对不同组具体处理。
dp[i][j]:第i种工作用去时间j能获取的最大幸福点(不装满的情况)。
状态转移公式:
1)最少选一个
最少选一个,初始化未选为-INF。
dp[i][l]=max3(dp[i][l],dp[i][l-c[i][j]]+g[i][j],dp[i-1][l-c[i][j]]+g[i][j]);
2)最多选一个
最多选一个,可以不选,初始化为上一组dp。
dp[i][l]=max(dp[i][l],dp[i-1][l-c[i][j]]+g[i][j]);
3)任意选
任意选,可以不选,初始化为上一组dp。
dp[i][l]=max(dp[i][l],dp[i][l-c[i][j]]+g[i][j]);

注~

一项工作只能完成一次。所以时间维度循环为递减(for(int l=T;l>=c[i][j];–l))。

#pragma comment(linker,"/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<iomanip>
#include<algorithm>
#include<numeric>
#include<functional>
#include<memory>
#include<cmath>
#include<cstring>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<vector>
#include<fstream>
#define min(a,b) (a)<(b)?(a):(b)
#define max(a,b) (a)>(b)?(a):(b)
#define lc(x) (x<<1)
#define rc(x) (x<<1|1)
const double pi=acos(-1.0);
const int INF=0x3f3f3f3f;
const int MAX=0x7fffffff;
const long long LINF=0x3f3f3f3f3f3f3f3f;
const long long LMAX=0x7fffffffffffffff;
const double eps=1e-9;
const int Mod=100007;
const int Max=10000005;
using namespace std;
int N,T;
int M[102],type[102];
int c[102][102],g[102][102];
int dp[102][102];
int max3(int a,int b,int c){
	return a>b?(a>c?a:c):(b>c?b:c);
}

int main() {
    freopen("data.in","r",stdin);
    cin.sync_with_stdio(false);
    cout.sync_with_stdio(false);
    while(cin>>N>>T){
    	for(int i=1;i<=N;++i){//read,type:0,最少选一个;1,最多选一个;2,任意选;
    		cin>>M[i]>>type[i];
    		for(int j=1;j<=M[i];++j){
    			cin>>c[i][j]>>g[i][j];
			}
		}

		memset(dp,0,sizeof(dp));
//		for(int i=0;i<=N;++i){
//			for(int j=0;j<=T;++j)
//			if(j==0)
//				dp[i][j]=0;
//			else
//				dp[i][j]=-INF;
//		}

		for(int i=1;i<=N;++i){
			if(type[i]==0){//最少选一个
				for(int j=0;j<=T;++j){
					dp[i][j]=-INF;
				}
				for(int j=1;j<=M[i];++j){
					for(int l=T;l>=c[i][j];--l){
							//if(dp[i][l-c[i][j]]>=0&&dp[i-1][l-c[i][j]]>=0)
								dp[i][l]=max3(dp[i][l],dp[i][l-c[i][j]]+g[i][j],dp[i-1][l-c[i][j]]+g[i][j]);
						}
				}
			}else if(type[i]==1){//最多选一个
				for(int j=0;j<=T;++j){
					dp[i][j]=dp[i-1][j];
				}
				for(int j=1;j<=M[i];++j){
					for(int l=T;l>=c[i][j];--l){
							dp[i][l]=max(dp[i][l],dp[i-1][l-c[i][j]]+g[i][j]);
					}
				}
			}else{//任意选
				for(int j=0;j<=T;++j){
					dp[i][j]=dp[i-1][j];
				}
				for(int j=1;j<=M[i];++j){
					//for(int l=0;l<=T;++l){
					//	if(l>=c[i][j])
					for(int l=T;l>=c[i][j];--l){
							dp[i][l]=max(dp[i][l],dp[i][l-c[i][j]]+g[i][j]);
					}
				}
			}
		}

		if(dp[N][T]>=0){
			cout<<dp[N][T]<<endl;
		}else{
			cout<<-1<<endl;
		}
	}

    fclose(stdin);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值