您的位置:首页 > 其它

HDU 3033 I love sneakers!(分组背包/至少选一个)

2016-04-03 16:21 495 查看
题目链接:

HDU 3033 I love sneakers!

题意:

有n个物品分成k组,每个物品都有相应的价格和价值,每组物品都至少得买一件。有m元,如果能把k组每组至少买一件输出用m元能买到的最大价值;否自输出Impossible。

分析:

01背包的变形–分组背包,而且是每组至少买一个的分组背包而不是每组至多只能买一个。

用dp[i][k]表示在前i组每组至少选一样,耗费k能获得的最大价值,

初始化dp[i][k]为-1,但是dp[i][k]=0,这样是为了在购买第一组时可以从dp[0]状态中选择。

状态转移方程:

if(dp[i][k-cost[i][j]]!=-1){//在第i组至少已经选一件商品
dp[i][k]=max(dp[i][k],dp[i][k-cost[i][j]]+val[i][j]);
}
if(dp[i-1][k-cost[i][j]]!=-1){//dp[i-1][k-cost[i][j]]!=-1保证前i-1组每组至少选一个
dp[i][k]=max(dp[i][k],dp[i-1][k-cost[i][j]]+val[i][j]);
}


这两个if是独立的,也就是不能用else if相连,因为第一个if是判断是否在第i组中同时买第j件和之前在i组中买的;第二个if是判断是否在第i组中只买第j件

注意k的遍历顺序应该是从M–>cost[i][j]因为是滚动数组。

//109MS 2008K
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX_N=110;
const int MAX_K=15;
const int MAX_M=10010;

int N,M,K;
int cost[MAX_K][MAX_N],val[MAX_K][MAX_N],num[MAX_K],dp[MAX_K][MAX_M];

int main()
{
//freopen("Din.txt","r",stdin);
while(~scanf("%d%d%d",&N,&M,&K)){
memset(num,0,sizeof(num));
for(int i=0;i<N;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
cost[a][num[a]]=b;
val[a][num[a]]=c;
num[a]++;
}
memset(dp,-1,sizeof(dp));
for(int i=0;i<MAX_M;i++) dp[0][i]=0;
for(int i=1;i<=K;i++){//dp[i][k]表示在前i组每组至少选一样,耗费k能获得的最大价值
for(int j=0;j<num[i];j++){
for(int k=M;k>=cost[i][j];k--){//注意k的遍历顺序!
if(dp[i][k-cost[i][j]]!=-1){//在第i组已经选一件商品
dp[i][k]=max(dp[i][k],dp[i][k-cost[i][j]]+val[i][j]);
}
if(dp[i-1][k-cost[i][j]]!=-1){//dp[i-1][k-cost[i][j]]!=-1保证前i-1组每组至少选一个
dp[i][k]=max(dp[i][k],dp[i-1][k-cost[i][j]]+val[i][j]);
}
//printf("i=%d j=%d k=%d dp[i][k]=%d\n",i,j,k,dp[i][k]);
}
}
}
if(dp[K][M]==-1) printf("Impossible\n");
else printf("%d\n",dp[K][M]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp hdu