本题的关键是将购物车问题转化为0-1背包问题,购物车的物品有主件和附件之分,而背包的物品没有这个限制,通过将附件物品转化为主件物品的状态,减少了物品数,增加了购买决策时的判断。
#include <stdio.h>
#include <string.h>
#define MAX(a,b) ((a>b)?a:b)
#define STATUS 4
/*
There are four statuses when we decide to buy one product.
First status: only buy it
Second status: buy it and its first accessory
Third status: buy it and its second accessory
Four status: buy it, first accessory and second accessory
So, we should decide which status is most valuable.
*/
int main(int argc, char* argv[]){
int N,m;
scanf("%d %d",&N,&m);
N /= 10; //all prices are all multiples of 10
int value[m][STATUS];
int cost[m][STATUS];
memset(value, 0, sizeof(value));
memset(cost, 0, sizeof(value));
int v, p, q;
for(int i=0; i<m;i++){
scanf("%d %d %d\n",&v, &p, &q);
v /= 10; //all prices are all multiples of 10
if(q == 0){
//status1: master product
value[i][0] = v * p;
cost[i][0] = v;
}
else if(cost[q-1][1] == 0){
//status2: first accessory
cost[q-1][1] = v;
value[q-1][1] = v*p;
}
else{
//status3: second accessory
cost[q-1][2] = v;
value[q-1][2] = v*p;
//status4: first accessory + second accessory
cost[q-1][3] = cost[q-1][1] + v;
value[q-1][3] = value[q-1][1] + v*p;
}
}
//add the cost and value of master to status2,3,4
for(int i=0; i<m; i++){
for(int j=1; j<STATUS; j++){
cost[i][j] = cost[i][0] + cost[i][j];
value[i][j] = value[i][0] + value[i][j];
}
}
// so makes m products to n products (n <= m)
// the serial number of products isn't changed
// if serial number i is a accessory, value[i][0] = 0, cost[i][0] = 0
int dp[m+1][N+1];
memset(dp, 0, sizeof(dp));
int max_value = 0;
for(int i=1; i<=m; i++){
for(int j=1; j<=N; j++){
max_value = dp[i-1][j];
for(int k =0; k<STATUS; k++)
{
if(cost[i-1][0] == 0){
// this serial number i-1 is a accessory
break;
}
else if(j < cost[i-1][0]){
// don't have enough money
break;
}
else if(k > 0 && cost[i-1][0] == cost[i-1][k]){
// don't have accessory
break;
}
else if(j >= cost[i-1][k]){
max_value = MAX(max_value,
dp[i-1][j-cost[i-1][k]] + value[i-1][k]);
}
}
dp[i][j] = max_value;
}
}
printf("%d\n", dp[m][N] * 10);
return 0;
}