//背包问题变形 #include #include int main(void) { int money, num; scanf("%d%d", &money, &num); int satisfy[60][4]; int value[60][4]; memset(satisfy, 0, sizeof(satisfy)); memset(value, 0, sizeof(value)); for (int i = 0; i < num; i++) { int v, p, q; scanf("%d%d%d", &v, &p, &q); if (q == 0)//如果i物品是主件 { value[i][0] = v; satisfy[i][0] = v * p; } else if (q != 0)//如果i物品是附件 { if (value[q - 1][1] == 0)//该物品是附件1 { value[q - 1][1] = v; satisfy[q - 1][1] = v * p; } else if (value[q - 1][1] != 0)//该物品是附件2 { value[q - 1][2] = v; satisfy[q - 1][2] = v * p; value[q - 1][3] = value[q - 1][2] + value[q - 1][1]; satisfy[q - 1][3] = satisfy[q - 1][2] + satisfy[q - 1][1]; } } } //二维数组需要补充主件价值 for (int i = 0; i < num; i++) { for (int j = 1; j < 4; j++) { if (value[i][0] != 0)//必须是主件才可以加 { value[i][j] += value[i][0]; satisfy[i][j] += satisfy[i][0]; } } } //开始动态规划 int dp[32000] = { 0 };//要选择用一维数组还是二维做动态规划,这里不知道主件的数量,所以使用一维数组 for (int i = 0; i < num; i++)//外循环为物品数量 { if (value[i][0] == 0)//不单独购买附件 continue; /*for (int k = 0; k <= 3; k++) { printf("%d ", satisfy[i][k]); }*/ for (int j = money; j >=0; j -= 10) //为什么不从0开始遍历? //因为会出现重复购买的情况,所以外层循环正向遍历物品,内层循环反向遍历背包容量 { for (int k = 0; k <= 3; k++)//遍历四种主件附件组合 { if (j >= value[i][k])//如果选择购买ik组合 { dp[j] = (dp[j] > satisfy[i][k] + dp[j - value[i][k]]) ? dp[j] : (satisfy[i][k] + dp[j - value[i][k]]); } } } } printf("%d", dp[money]); return 0; }