这类似于我需要的算法...
我想购买一整套交易卡-每张卡中的一张。
可以从不同的供应商以不同的价格购买每张卡。如果我从某个供应商处购买了给定的卡,他们有时会捆绑提供一个或多个附加卡,以收取额外费用。捆绑包有时可以提供很大的折扣,但是有些供应商出售的单价真的很便宜,不需要捆绑包。
如果我对每个供应商的每张卡和捆绑包都有完整的价目表,有人可以建议一种算法,该算法可以有效地计算(或近似)购买整套卡的最便宜方法吗?
答案 0 :(得分:0)
首先,我的直觉告诉我,这至少是一个NP难题。我认为您无法检查提供的购物车是否实际上是多项式时间内最便宜的。如果您从其他供应商处购买了一张卡并选择了完全不同的捆绑包,则可能会丢失卡。现在,您可以从其他供应商那里购买那些丢失的卡,以获得新的捆绑销售商品,从而导致整个零钱。
我将尝试使用近似解决方案来拟定针对已知NP问题的应用程序。
好吧,所以您不仅知道卡和捆绑包的价格,而且确切地知道需要购买哪些卡才能激活捆绑包的优惠。
听起来您可以在此处改编(修改过的)最小生成树(MST)算法。
这就是我认为您应该形成自己的DIRECTED图的方式:
C
。CV
。CV
作为源连接到C
作为目标。权重为0。CV
,创建一个节点BCV
。用捆绑包的价格从CV
到BCV
连接。BCV
,以0的权重连接到该捆绑包中的所有C
。CV
的节点,每个权重等于该卡的供应商价格。根据此公式,您需要一个仅需要到达类型C
的节点的MST。该MST会告诉您要购买哪些卡以及要购买哪些捆绑包。如果您连接到卡CV
,则意味着您已经获得了相应的C
(权重为0,因此它们是免费的)。如果另外选择连接到相应的BCV
,则可以免费连接到该捆绑包中的所有C
。
事实证明,这些类型的树称为Steiner树,并且已知为NP硬树。我通过Google搜索找到的This paper和this paper似乎提供了一种近似算法。您还可以查找更多内容。但是,看起来似乎没有人实际在某种易于使用的Python包中实现此功能。
答案 1 :(得分:0)
您可以找到具有凸优化的近似解(在某些情况下,还可以是完整解)。诀窍在于您可能不必将购买的卡数限制为整数,因为无论如何最佳数目通常都是整数。问题设置:
说整套中有N张卡。为每张卡分配一个索引,从0到N-1。
对于每个可能的捆绑购买i,创建一个长度为N的向量 Cards i ,在其包含的卡片索引处为1,在所有其他索引处为0。 / p>
此外,捆绑购买的价格为 Price i 。您的免费优化变量是 Choice i 。
因此,每个束具有2个常量和1个优化变量。那么您的优化问题是:
最小化总和(价格 i * 选择 i )
主题:
sum(卡 i * 选择 i )> =个(N,1)
选择 i > = 0
一个(N,1)是您要拥有的卡数的要求。
您应该能够使用cvxpy库很容易地进行设置:http://www.cvxpy.org/解决之后,您需要检查其生成的 Choice i 变量都接近于0或接近于1。如果不是,则意味着您的数据具有束的病理组合,如以下mcdowella的评论所述。在这种情况下,您需要按照其他答案所述进行NP硬搜索。或者,您也可以进行破解,例如单独购买这些卡并接受其不能保证达到最佳状态。