算法-购物车问题

文章讨论了一个在线购物场景中如何在有限预算下最大化满意度的问题,涉及主物品和附件的关系、物品价格和重要性的计算,以及使用背包问题的算法模型。作者给出了具体代码实现,展示了如何模拟购买决策和优化解决方案。
摘要由CSDN通过智能技术生成

算法-购物车问题

问题描述

终于发了年终奖准备去网上购物,如何能在有限的预算内,得到最大的收益呢。如果只到这里的话,其实就是一个背包问题,可以参考链接

然鹅还有其他条件:

可以购买的物品分为两类:主物品可以单独购买,附件物品只能在已经购买了主物品的情况下购买。例如,要购买打印机,需要先购买电脑。另外,一个主件商品,最多有2个附件商品。

计算满意度=物品价格*物品重要性

其实还有一个默认条件,那就是每个物品默认只购买一次。想想也很合理,又不是消耗品,多买只会降低边际效应。

问题抽象

用代码来抽象表示,大概如下这样

# 总预算1000,可选商品数量5个
m = 1000
n = 5

物品价格和重要性,以及主附关系如下:(题目还有个提示是,价格都是10的倍数

# 价格 重要性 主件还是附件,1说明他们是第一件物品的附件
goods = [
    [800, 2, 0],
    [400, 5, 1],
    [300, 5, 1],
    [400, 3, 0],
    [500, 2, 0]
]

问题分解

因为最终考虑的是商品的满意度,也就是计算价格*重要度,所以先对商品数据做处理

def get_value(price, point):
    """计算价格和满意度"""
    value_ = [price, price*point]
    return value_
  • 每次考虑是否购入一种商品时,因为附件至多有2个,有以下4种情况:
  1. 只购买主件
  2. 购买主件+附件1
  3. 购买主件+附件2
  4. 购买主件+附件1+附件2
def work(key, value, attachments):
    """模拟4种情况"""
    prices, points = [], []
    # 1.仅有主件
    prices.append(value[0])
    points.append(value[1])
    if key in attachments:
        # 2. 主件 + 附件1
        prices.append(prices[0] + attachments[key][0][0])
        points.append(points[0] + attachments[key][0][1])
        if len(attachments[key]) == 2:
            # 3.主件+附件2
            prices.append(prices[0] + attachments[key][1][0])
            points.append(points[0] + attachments[key][1][1])
            # 4.主件+ 附件1 + 附件2
            prices.append(prices[0] + attachments[key][0][0] + attachments[key][1][0])
            points.append(points[0] + attachments[key][0][1] + attachments[key][1][1])
    return prices, points

用2个字典分别存储主件和附件,一个res列表存储最优解

    # 主件 附件 结果列表
    main_goods, attachments, res_list = {}, {}, [0] *(m+1)
  • 遍历商品,将主件和附件,分别添加进字典
    for i in range(n):
        price, point, att = goods[i][0], goods[i][1], goods[i][2]
        # 把商品简化成价格 和  满意度
        good = get_value(price, point)
        # 如果是主件
        if att == 0:
            # 添加进主件字典, 注意i+1,这样就和附件的主件对应上了
            main_goods[i+1] = good
        # 如果是附件    
        else:
            # 如果该附件编号key已经存在了
            if att in attachments:
                # 这个key下的列表,加上该附件商品
                attachments[att].append(good)
            # 不存在就创建这个key   
            else:
                attachments[att] = [good]
  • 最终,对主件商品进行遍历,计算每个预算的结果,这里类似于背包问题里一行内的值计算
    # 对主件字典进行遍历
    for key, value in main_goods.items():
        # prices列表和points列表,分别计算了4种情况的价格和满意度
        prices, points = work(key, value, attachments)
        # 对一列的所有值进行遍历
        for j in range(m, -1, -10):  # 价格是10的倍数
            # 判断价格是否在预算内
            for k in range(len(prices)):
                # 如果在预算内
                if j - prices[k] >= 0:
                    # 最优解在 上一次的最优解 和 剩余预算的最优解+当前满意度 之间取大的那个
                    res_list[j] = max(res_list[j], res_list[j-prices[k]] + points[k])

最后返回结果,

    return res_list[m]

完整代码如下

def get_value(price, point):
    """计算价格和满意度"""
    value_ = [price, price*point]
    return value_

def work(key, value, attachments):
    """模拟4种情况"""
    prices, points = [], []
    # 1.仅有主件
    prices.append(value[0])
    points.append(value[1])
    if key in attachments:
        # 2. 主件 + 附件1
        prices.append(prices[0] + attachments[key][0][0])
        points.append(points[0] + attachments[key][0][1])
        if len(attachments[key]) == 2:
            # 3.主件+附件2
            prices.append(prices[0] + attachments[key][1][0])
            points.append(points[0] + attachments[key][1][1])
            # 4.主件+ 附件1 + 附件2
            prices.append(prices[0] + attachments[key][0][0] + attachments[key][1][0])
            points.append(points[0] + attachments[key][0][1] + attachments[key][1][1])
    return prices, points

def main():
    # 总预算1000, 可选商品5
    m, n = 1000, 5
    # 商品的价格 重要度 是否附件
    goods = [
        [800, 2, 0],
        [400, 5, 1],
        [300, 5, 1],
        [400, 3, 0],
        [500, 2, 0]
    ]
    # 主件 附件
    main_goods, attachments, res_list = {}, {}, [0] * (m+1)
    for i in range(n):
        price, point, att = goods[i][0], goods[i][1], goods[i][2]
        # 把商品简化成价格 和  满意度
        good = get_value(price, point)
        # 如果是主件
        if att == 0:
            # 添加进主件字典
            main_goods[i+1] = good
        # 如果是附件
        else:
            # 如果该附件编号key已经存在了
            if att in attachments:
                # 这个key下的列表,加上该附件商品
                attachments[att].append(good)
            # 不存在就创建这个key
            else:
                attachments[att] = [good]

    # 对主件字典进行遍历
    for key, value in main_goods.items():
        # prices列表和points列表,分别计算了4种情况的价格和满意度
        prices, points = work(key, value, attachments)
        # 对一列的所有值进行遍历
        for j in range(m, -1, -10):  # 价格是10的倍数
            # 判断价格是否在预算内
            for k in range(len(prices)):
                # 如果在预算内
                if j - prices[k] >= 0:
                    # 最优解在 上一次的最优解 和 剩余预算的最优解+当前满意度 之间取大的那个
                    res_list[j] = max(res_list[j], res_list[j-prices[k]] + points[k])
    print(res_list)
    return res_list[m]

if __name__ == '__main__':
    print(main())

参考了如下链接:https://blog.csdn.net/kk_gods/article/details/116048116

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值