hdu 3033 分组背包(每组至少选一个)
题意:有个小娃娃得了奖学金要去买东西,一共有n个东西分为k组,每个东西有一个花费和价值,问在每组东西至少买一个的条件下,小娃娃用他的奖学金买东西可以获得的最大价值。
思路:定义状态dp[i][v]表示在[1, i]组物品都至少有一个被购买时用v(背包容量)这么多钱能得到多少价值。
状态转移方程:
if ( dp[i][v - cost[i][j]] != -1 )
dp[i][v] = max( dp[i][v], dp[i][v - cost[i][j]] + val[i][j] );
if ( dp[i - 1][v - cost[i][j]] != -1 )
dp[i][v] = max( dp[i][v], dp[i - 1][v - cost[i][j]] + val[i][j] );
分别表示第i组的物品不是和是第一次购买。
这两个状态转移方程顺序不能变,因为有花费是0的物品...
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 101; 7 const int M = 10001; 8 const int K = 11; 9 int dp[K][M]; 10 int cost[K][N]; 11 int val[K][N]; 12 int num[K]; 13 14 int main () 15 { 16 int n, m, k; 17 while ( scanf("%d%d%d", &n, &m, &k) != EOF ) 18 { 19 memset( num, 0, sizeof(num) ); 20 for ( int i = 1; i <= n; i++ ) 21 { 22 int g; 23 scanf("%d", &g); 24 scanf("%d%d", &cost[g][num[g]], &val[g][num[g]]); 25 num[g]++; 26 } 27 memset( dp, -1, sizeof(dp) ); 28 memset( dp[0], 0, sizeof(dp[0]) ); 29 for ( int i = 1; i <= k; i++ ) 30 { 31 for ( int j = 0; j < num[i]; j++ ) 32 { 33 for ( int v = m; v >= cost[i][j]; v-- ) 34 { 35 if ( dp[i][v - cost[i][j]] != -1 ) 36 { 37 dp[i][v] = max( dp[i][v], dp[i][v - cost[i][j]] + val[i][j] ); 38 } 39 if ( dp[i - 1][v - cost[i][j]] != -1 ) 40 { 41 dp[i][v] = max( dp[i][v], dp[i - 1][v - cost[i][j]] + val[i][j] ); 42 } 43 } 44 } 45 } 46 if ( dp[k][m] != -1 ) 47 { 48 printf("%d\n", dp[k][m]); 49 } 50 else 51 { 52 printf("Impossible\n"); 53 } 54 } 55 return 0; 56 }