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

来源:互联网 发布:如何看待人工智能 编辑:程序博客网 时间:2024/06/07 15:30

题目链接:
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;}
0 0
原创粉丝点击