某公司游戏平台的夏季特惠开始了,你决定入手一些游戏。现在你一共有X元的预算,该平台上所有的 n 个游戏均有折扣,标号为 i i i 的游戏的原价 a i a_i ai元,现价只要 b i b_i bi 元(也就是说该游戏可以优惠 a i − b i a_i - b_i ai−bi元)并且你购买该游戏能获得快乐值为 w i w_i wi。由于优惠的存在,你可能做出一些冲动消费导致最终买游戏的总费用超过预算,但只要满足获得的总优惠金额不低于超过预算的总金额,那在心理上就不会觉得吃亏。现在你希望在心理上不觉得吃亏的前提下,获得尽可能多的快乐值。
代码:
#include <stdio.h>
#include <stdlib.h>
// 贪心法
void quikSort(int *index, int * happy, int start, int end) {
if (start < end) {
int left = start, right = end;
int target = index[start];
int tmp = happy[index[start]];
while (left < right) {
while (left < right && tmp >= happy[index[right]]) right--;
if (left < right) {
index[left] = index[right];
left++;
}
while (left < right && tmp <= (happy[index[left]])) left++;
if (left < right) {
index[right] = index[left];
right--;
}
}
index[right] = target;
quikSort(index, happy, start, right - 1);
quikSort(index, happy, right + 1, end);
}
}
int main () {
int n = 0, money = 0;
scanf("%d %d", &n, &money);
int *value = malloc(sizeof(int) * n); // 优惠后价格
memset(value, 0, n);
int *happy = malloc(sizeof(int) * n); // 快乐值
memset(happy, 0, n);
int *disocunt = malloc(sizeof(int) * n); // 优惠金额
memset(disocunt, 0, n);
int *index = malloc(sizeof(int) * n); // 下标,用于后续的排序
memset(index, 0, n);
for (int i = 0; i < n; i++) {
int a = 0, b = 0, c = 0;
scanf("%d %d %d", &a, &b, &c);
value[i] = b;
happy[i] = c;
disocunt[i] = a - b;
index[i] = i;
}
quikSort(index, happy, 0, n - 1);
int maxhappy = 0;
for (int i = 0; i < n; i++) {
int a = index[i];
if (money < value[a]) continue;
maxhappy += happy[a];
money = money - value[a] + disocunt[a];
// printf("%d %d %d\n", a, money, maxhappy);
}
printf("%d", maxhappy);
return 0;
}
最终目标是使快乐值最大,首先想到的是贪心法,首先以每件商品的 快乐值/优惠价 进行贪心(计算时因为数据比较小,结果可能都为0,所以将其强制转换为 float),但是发现效果并不怎么好;以快乐值进行贪心同样的也是。
可以用的钱是可以变化的,题目中提到,当超出预算的金额不多于总优惠的金额时,同样也是快乐的,最终解回跟选择的顺序有关(可能购买某一样超出了预算,但是先购买其他的,总优惠金额超过了超出的预算,就可以购买这个了,还要回头遍历这个)
这个题目是一个0/1背包问题,但是又不是0/1背包问题,因为它的容量是可以变化的,不是固定的。所以使用动态规划的话不好设置,且其数值也比较大。
回顾一下0/1 背包的动态规划解法:
假设一个背包容量是
c
,有n
个物品,其价值和体积分别为: [ [ w 1 , v 1 ] , [ w 2 , v 2 ] , . . . , [ w n , v n ] ] [[w_1, v_1], [w_2, v_2],...,[w_n, v_n]] [[w1,v1],[w2,v2],...,[wn,vn]],挑选物品使其价值最大。
就可以构建一个 (n+1)*(c+1)
的二维数组。第一行第一列初始化为 0。
遍历这个二维数组 value[i][j]
, 其含义就是当前情况下的价值最大。其有两种情况,即要不要第 i 个物品,判断 value[i-1][j]
和
v
a
l
u
e
[
i
−
1
]
[
j
−
v
i
]
+
w
i
value[i-1][j-v_i]+w_i
value[i−1][j−vi]+wi(前者表示不选择第i个物品时的最大价值,后者表示选择第i个物品时的最大价值),比较其大小,选择一个大值填入。
value[n][c]
的值就是所能得到的最大价值。
而在这个题目中,并不能确定挑选物品的顺序,物品挑选的顺序会影响其结果。