hdu 3033
地址:http://acm.hdu.edu.cn/showproblem.php?pid=3033
题意:一个人买商品,必须每个种类的商品至少买一件,同时保证买到的价值尽可能大,如果不能满意,输出Impossible。
mark:分组背包的变种,普通分组背包是一个组里面最大取一件,这题是至少取一件。
设计状态dp[i][j]代表前i组容量为j的最大价值。由于一组里面有多个物品,所以状态转移可以是前一组少取一个,即dp[i-1][p-g[i][j].v]+g[i][j].w,也可以是当前组之前去过的少取一种,即dp[i][p-g[i][j].v]+g[i][j].w。
网上有些解题报告是错误的解法,这题dp初始化的时候要初始化为负无穷,因为这题要求的是上一组恰好达到的状态才能转移到这一组来,因为每一组至少得去一个。当然可以初始化为-1,每次判断一下是不是-1就行。
代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct { int v,w; }goods; const int N = 110; const int M = 10010; int n,m,k; goods g[15][N]; int num[15]; int dp[15][M]; int min(int a, int b) {return a < b ? a : b;} int max(int a, int b) {return a > b ? a : b;} int main() { int i,j; while(~scanf("%d%d%d", &n, &m, &k)) { int aa,bb; memset(num, 0, sizeof(num)); for(i = 1; i <= n; i++) { scanf("%d%d%d", &j, &aa, &bb); g[j][num[j]].v = aa; g[j][num[j]].w = bb; num[j]++; } memset(dp, -1, sizeof(dp)); memset(dp[0], 0, sizeof(dp[0])); for(i = 1; i <= k; i++) { for(j = 0; j < num[i]; j++) for(int p = m; p >= g[i][j].v; p--) { if(dp[i][p-g[i][j].v] != -1) dp[i][p] = max(dp[i][p], dp[i][p-g[i][j].v]+g[i][j].w); if(dp[i-1][p-g[i][j].v] != -1) dp[i][p] = max(dp[i][p], dp[i-1][p-g[i][j].v]+g[i][j].w); } } if(dp[k][m] < 0) puts("Impossible"); else printf("%d\n", dp[k][m]); } return 0; }