/* http://acm.hdu.edu.cn/showproblem.php?pid=3236 Gift Hunting 题意:某人有两张卡,卡上的钱不能合并消费,买东西的时候物品有两个属性,一个是必须买的(即girlfriend need) 还有一个不是必须买的,同一样物品用不同的卡消费相同并且只能购买一次,我们需要最大的价值(即happy值). 思路: 分组背包,现将必买的东西用分组背包处理一次,判断获取的最后的价值是否为全部拿到的价值。 然后再处理不必须购买的物品,转移状态时必须确保必须购买的不能漏去了。 因此我们只需判断 dp[j][k-cost][q] >= sp_sum 在放进物品之前最大的价值是否大于 必须品全部的价值 即可 */ #pragma comment(linker, "/stack:64000000") #define _CRT_SECURE_NO_DEPRECATE #include <queue> #include <cmath> #include <cstdio> #include <string> #include <cstring> #include <iostream> using namespace std; #define CLR(c,v) memset(c,v,sizeof(c)) template <typename _T> _T Max(_T a , _T b){ return (a>b)?(a):(b); } template <typename _T> _T Max(_T a , _T b, _T c){ return (a>Max(b,c))?(a):(Max(b,c)); } template <typename _T> _T Min(_T a , _T b){ return (a<b)?(a):(b); } template <typename _T> _T Min(_T a , _T b, _T c){ return (a<Min(b,c))?(a):(Min(b,c)); } const int inf = -(1<<30); const int INF = (1<<30); const double eps = 1e-8; const int V1_M = 5e2 +1; const int V2_M = 50 +1; const int M = 3e2 +1; int v[M]; int c[M]; int sp[M]; // 特殊的下标 int np[M]; // 普通的下标 int sp_len, np_len; int sp_sum; int dp[V1_M][V2_M][2]; int n_row , max_cost1, max_cost2, max_free; bool solve(int p[],int len,int is_sp){ for(int i = (is_sp==1)?(1):(sp_len+1) ; i <= len ; i++){ int cost = (is_sp==1)?(c[sp[i]]):(c[np[i-sp_len]]); int value = (is_sp==1)?(v[sp[i]]):(v[np[i-sp_len]]); for (int j = max_cost1 ; j >= 0 ; j-- ){ for (int k = max_cost2 ; k >= 0 ; k-- ){ for (int q = max_free ; q >= 0 ; q-- ){ int v1,v2,v3; if(is_sp==1){ v1 = (j >= cost)?( dp[j-cost][k][q] + value):(0); v2 = (k >= cost)?( dp[j][k-cost][q] + value):(0); v3 = (q >= 1 )?( dp[j][k][q-1] + value):(0); }else{ v1 = (j >= cost && dp[j-cost][k][q] >= sp_sum)?( dp[j-cost][k][q] + value):(0); v2 = (k >= cost && dp[j][k-cost][q] >= sp_sum)?( dp[j][k-cost][q] + value):(0); v3 = (q >= 1 && dp[j][k][q-1] >= sp_sum)?( dp[j][k][q-1] + value):(0); } dp[j][k][q] = Max(dp[j][k][q] , Max(v1,v2,v3)); } } } } if(is_sp && sp_sum > dp[max_cost1][max_cost2][1]) return false; return true; } void Init(){ CLR(dp,0); CLR(sp,0); CLR(np,0); sp_sum = 0; sp_len = 0; np_len = 0; max_free = 1; } int main(){ //freopen("in.txt","r",stdin); int Ncase = 1, s; while(cin >> max_cost1 >> max_cost2 >> n_row, max_cost1 && max_cost2 && n_row){ Init(); for (int i = 1 ; i <= n_row ; i ++){ cin >> c[i] >> v[i] >> s; if(s == 1){ sp[++sp_len] = i; sp_sum += v[i]; }else{ np[++np_len] = i; } } if(solve(sp , sp_len , 1)){ // 先处理特殊的,如果全部价值拿到了则继续 solve(np , n_row , 0); }else{ dp[max_cost1][max_cost2][1] = -1; } printf("Case %d: %d\n\n",Ncase++ ,dp[max_cost1][max_cost2][1]); } return 0; } /* 3 2 4 3 10 1 2 10 0 5 100 0 5 80 1 3 2 4 3 10 1 2 10 0 5 100 0 5 80 0 3 2 4 3 10 1 2 10 1 5 100 1 5 80 1 8 2 4 3 10 0 2 10 0 5 100 0 5 80 0 0 0 0 result: Case 1: 100 Case 2: 120 Case 3: -1 Case 4: 200 */