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;
}