算法:夏季特惠

leetcode 夏季特惠

在这里插入图片描述

某公司游戏平台的夏季特惠开始了,你决定入手一些游戏。现在你一共有X元的预算,该平台上所有的 n 个游戏均有折扣,标号为 i i i 的游戏的原价 a i a_i ai元,现价只要 b i b_i bi 元(也就是说该游戏可以优惠 a i − b i a_i - b_i aibi元)并且你购买该游戏能获得快乐值为 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[i1][jvi]+wi(前者表示不选择第i个物品时的最大价值,后者表示选择第i个物品时的最大价值),比较其大小,选择一个大值填入。

value[n][c] 的值就是所能得到的最大价值。


而在这个题目中,并不能确定挑选物品的顺序,物品挑选的顺序会影响其结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值