题目链接:
HDU 3535 AreYouBusy
题意:
有n组物品,有三种组:①:组中物品必须买一个;②:组中物品最多买一个;③:组中物品随便买。每个物品只能买一次,问给m元钱能得到的最大价值是多少?如果无法得到最大价值,即有的组该买而无法买,那就输出-1.
分析:
混合背包和分组背包。
分两部分解决,一部分是分组背包,即每组中必须买一个;另一部分是至多买一个和随便买。然后最终只需要遍历一下两部分满足条件的所有能到的最大价值相加取最大就好了。
注意:
下面代码的中的
for(int j=0;j<=total;j++){ dp2[i][j]=dp2[i-1][j]; }
本来是用
dp2[i][k]=max(dp2[i][k],dp2[i-1][k]);
代替的,WA了好多发,如果是
dp2[i][k]=max(dp2[i][k],dp2[i-1][k]);
处理的话,那么对于
dp2[i][k]=max(dp2[i][k],dp2[i][k-task[i].cost[j]]+task[i].val[j]);
就有一个问题:在处理第一件物品的时候, dp2[i][k−task[i].cost[j]] 是0!而实际上应该是前面i-1组用 k−task[i].cost[j] 能得到的最大价值!o(╯□╰)o
//1604K 31MS
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX_N=110;
int n,total;
int dp1[MAX_N][MAX_N],dp2[MAX_N][MAX_N];
struct Task{
int num,flag;
int cost[MAX_N],val[MAX_N];
bool operator < (const Task a) const {
if(flag!=a.flag) return flag<a.flag;
else return num<a.num;
}
}task[MAX_N];
int main()
{
freopen("hdu3535in.txt","r",stdin);
while(~scanf("%d%d",&n,&total)){
int zero_num=0;
for(int i=1;i<=n;i++){
scanf("%d%d",&task[i].num,&task[i].flag);
if(task[i].flag==0) zero_num++;
for(int j=0;j<task[i].num;j++){
scanf("%d%d",&task[i].cost[j],&task[i].val[j]);
}
}
sort(task+1,task+n+1);
memset(dp1,-1,sizeof(dp1));
memset(dp1[0],0,sizeof(dp1[0]));
for(int i=1;i<=zero_num;i++){
for(int j=0;j<task[i].num;j++){
for(int k=total;k>=task[i].cost[j];k--){
if(dp1[i][k-task[i].cost[j]]!=-1) {
dp1[i][k]=max(dp1[i][k],dp1[i][k-task[i].cost[j]]+task[i].val[j]);
}
if(dp1[i-1][k-task[i].cost[j]]!=-1){
dp1[i][k]=max(dp1[i][k],dp1[i-1][k-task[i].cost[j]]+task[i].val[j]);
}
}
}
}
if(dp1[zero_num][total]==-1){
printf("-1\n");
continue;
}
//printf("zero:%d\n",dp1[zero_num][total]);
memset(dp2,0,sizeof(dp2));
for(int i=zero_num+1;i<=n;i++){
for(int j=0;j<=total;j++){
dp2[i][j]=dp2[i-1][j];
}
for(int j=0;j<task[i].num;j++){
for(int k=total;k>=task[i].cost[j];k--){
//dp2[i][k]=max(dp2[i][k],dp2[i-1][k]);
if(task[i].flag==1) //至多只能选一件
dp2[i][k]=max(dp2[i][k],dp2[i-1][k-task[i].cost[j]]+task[i].val[j]);
else {//不限制取件量
dp2[i][k]=max(dp2[i][k],dp2[i][k-task[i].cost[j]]+task[i].val[j]);
}
//printf("i=%d j=%d k=%d dp[i][k]=%d\n",i,j,k,dp2[i][k]);
}
}
}
int ans=0;
for(int i=0;i<=total;i++){
if(dp1[zero_num][i]!=-1){
ans=max(ans,dp1[zero_num][i]+dp2[n][total-i]);
}
}
printf("%d\n",ans);
}
return 0;
}