找到最佳的项目组合,以最低的成本。也许是背包变种?

时间:2016-12-14 15:43:11

标签: recursion dynamic-programming knapsack-problem

故事

我想让我的祖母出名的N-bean汤。该食谱正好需要N豆。

杂货店只出售预包装袋中的豆子。每个袋子包含特定数量的豆子,价格不同。

1000 for $300 ($.3 per bean) 750 for $225 ($.3 per bean) 600 for $180 ($.3 per bean)

300 for $150 ($.5 per bean) 250 for $125 ($.5 per bean) 100 for $50 ($.5 per bean)

10 for $10 ($1 per bean) 5 for $5 ($1 per bean) 1 for $1 ($1 per bean)

一项联邦食品杂志法规定,一袋较大的咖啡豆永远不会比一个较小的咖啡包更昂贵的每豆成本,但它可以是相同的。简而言之,袋中的豆越多,价值越高。

当我去商店时,我需要确保为食谱购买至少N豆。我也想花尽可能少的钱。如果我购买的豆子比我需要的更多,我也不在乎,我只是想确保得到最好的交易。 我想以尽可能低的价格购买能给我至少N豆的袋子组合。

我想做什么?

我试图写一个能够快速计算出来的算法。不幸的是,我需要在我正在编写的游戏中经常调用它,您可以在其中拖动值滑块来更改配方所需的Bean数量。

这个问题非常接近背包问题或制作改变问题,但不同,因为我不关心我拍摄的物品数量,而是关心总成本。我认为动态编程是一种可行的方式,但我对它的理解还不足以开始将问题分解成更小的块。

这就是我目前的想法:我想编写一个功能,创建一组可能的Bean Bag购买。我想首先评估大量(最高价值)袋子。我必须自上而下,因为根据联邦法律,自下而上会创造低价值的结果,我知道会更贵。

我想创建一个在购买每个行李时分支的功能,并计算如果我做了会发生什么,或者不再买一个特定的行李,然后继续计算。它从最昂贵的袋子开始,逐渐降低

我认为我应该将这些可能的组合存储为二维数组,其中"列"是您购买的行李数量,每行代表一个完整的行李组合,以达到目标豆类数量。在计算出可能的有效交易之后,我可以通过2D阵列进行咀嚼,找到总成本最低的那个,如果其中有几个是相同的,我选择总买入数量最少的一个。

我认为我的代码会做什么

例如,让我们说我的食谱需要1602个豆子。我首先购买2x1000袋,共计600美元。这是有效的购买,但也许不是最好的交易。购买第3个1000计数的包将无效,所以我改为分支,只购买1x1000计数包和1x750计数,总计525.更好的交易!然后我再次分支,购买1x1000 + 2x600 = 660美元,这更糟糕。再次分支:1x1000 + 1x600 + 1x300 = 630美元。依此类推,直到我以482美元的价格达到1x1000 + 1x600 + 2x1。这是最好的交易,但我还不知道,我必须咀嚼下一个分支点。

问题

我的一个大问题是:我认为我可以写一个递归循环来评估每一个可能的购买。但是,我怎么知道什么时候能够安全地摆脱这个循环呢?在什么时候我可以肯定地说#34;好吧,最后一个分支证明我没有必要进一步计算,我找到了最好的交易。让我们现在停下来,节省时间"

这种问题有名吗?它是背包问题的某种变体吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

是的,这是对Knapsack地区的宽松解释。

<强>详情

首先,使用动态编程:保存数组中每次调用的结果。 从不第二次计算该值。

您的基本截止点是当您尝试购买与已经在解决方案中的其他人结合的麻袋时,等于更大麻袋的数量。保释解决方案;一个更高的分支会找到更大的麻袋。

请注意,这适用于组合解决方案:每次返回后检查。例如,如果您归结为7个bean,则您的呼叫将返回(5,1,1)。如果你已经在更高的解决方案中有一个5-bean包,放弃那个分支 - 更高的分支将(或已经)找到10-bean解决方案。

高级处理

如果您事先确定基本组合,您可以建立一个快捷列表:三个100豆袋制作300等。这使您可以主动限制任何解决方案路径中的100豆袋数量。然而,在一般的混乱环境中,这并没有多大帮助,因为大多数数量不会分裂另一个。我不会为混合组合而烦恼,因为在每次返回时测试多次匹配会使代码复杂化而几乎没有回报。

<强>测试

请务必尝试一些最大的包和一些小包比中型包组合更贵的情况。

尝试一些奇怪的案例:权力为2,斐波那契数量,素数等等。