购买最大物品的算法

时间:2012-05-08 23:11:53

标签: algorithm

我们有N金币和M银币。有k个项目,每个都有一些成本,一个金币和B银币,其中A或B也可以为零。

什么算法可以购买最大数量的物品?

3 个答案:

答案 0 :(得分:4)

这是背包问题吗?

您描述的问题不是Knapsack problem。在这里,您只想最大化项目数量,而不是总成本。在背包问题中,你感兴趣的是最大化总成本,同时尊重麻袋的容量。换句话说,你想要抓住适合你口袋的最有价值的物品。你真的不关心它们中有多少,只是它们是最有价值的那些!

下面,我们将讨论问题的两个变种:

  1. 单一货币 - 金币和银币是可互换的
  2. 多个正交货币 - 金币无法转换为白银。
  3. 单一货币变式

    假设你只允许花N金币和M银币,这里有一个应该有效的算法:

    1. Sort the items by cost, from cheapest to the most expensive.
    2. totalCost = 0; i = 1
    3. while totalCost <= goldToCost(N) + silverToCost(M) + item[i].cost
    4.    totalCost = totalCost + items[i].cost
    5.    i++
    6. endWhile
    7. return i
    

    由于排序,此算法仅占用 O(nlogn)时间。

    多货币变式

    上述解决方案假设两种货币可以相互转换。该问题的另一个变体涉及正交货币,其中两种货币不能相互转换。在这种情况下,所有成本都将被指定为向量。

    为了使用动态编程算法解决这个问题。我们需要询问是否展示以下两个特征:

    1. Optimal Substructure。问题的最佳解决方案是从其子问题的最优解决方案中得出的吗?例如,让S(M, N)成为我们可以使用M金币和N银币购买的最大物品数量。我们可以使用递归关系推导出S(M, N)吗?
    2. overlapping Subproblems。是否使用S(M,N)的子问题反复计算更大的子问题?
    3. 想象一下具有N行和M列的二维表。

      +---+---+---+---+---+-----+---+
      |   | 0 | 1 | 2 | 3 | ... | N |
      +---+---+---+---+---+-----+---+
      | 0 |   |   |   |   |     |   |
      | 1 |   |   |   |   |     |   |
      | 2 |   |   |   |   | ... |   |
      | 3 |   |   |   |   |     |   |
      | : |   |   |   |   |     |   |
      | M |   |   |   |   |     |   |
      +---+---+---+---+---+-----+---+
      

      我们的算法基本上会填写此表。在行i,列j S[i, j]中,可以使用我的金币和j银币购买最大数量的商品。

      要完成该表,我们可以使用两个按字典顺序排序的数组ID。在第一个,黄金作为主要的排序关键,银色seconday。在第二,银是主要的,黄金是次要的。填写第0行和第3列是直截了当的。然后我们串联遍历两个排序的数组,然后我们可以使用以下重复来完成表

      S[0, 0] = 0
      S[i, j] = 0   if i < 0 or j < 0 
      S[i, j] = max(S[i-1,j-1] + d[i-1,j-1], S[i-1,j] + d[i-1,j], S[i,j-1] + d[i,j-1])
      

      其中d[i*,j*]是您可以使用<i,j> - <i*, j*>购买的其他项目数,其中<i*, j*>{<i-1, j-1>, <i-1, j>, <i, j-1>}之一。换句话说,你可以用剩余的钱购买多少钱。对此进行计算的搜索涉及对两个按字典顺序排序的序列之一(ID)进行二进制搜索。

      此解决方案需要 O((MN + n)logn)时间来计算并使用 O(MN + n)空间。

答案 1 :(得分:4)

在这个问题中,每个项目都有二维成本。让项目i有成本c [i] = &LT; a,b>其中a是金币的成本,b是银币的成本。

这些项目现在可以部分订购,以便项目i比项目j“不是更贵”,如果

c[i] = <a, b>    c[j] = <a', b'>  and    a <= a' AND b <= b'

请注意,这是部分订单。两个项目&lt; 1,2&gt;和&lt; 2,1&gt;在这种偏序中没有可比性;没有一个比另一个更贵。

现在很清楚,贪婪算法可以安全地购买物品,只要它们“不是更贵”,而每个其他剩余物品,但是当有多个不可比项目时可用,可能需要更多分析(例如搜索)。

例如,如果费用是

 <1, 1>
 <2, 1>
 <1, 2>
 <3, 3>

这导致了这个部分顺序:

        <1, 1>
       /      \
     <2, 1>   <1, 2>
         \   /
         <3, 3>

(底部最贵的物品)。贪婪算法将首先购买&lt; 1,1&gt;。之后,&lt; 2,1&gt;都是&lt; 2,1&gt;。和&lt; 1,2&gt;是可行的购买选择。如果算法选择购买&lt; 2,1&gt;,则下一个购买是&lt; 1,2&gt;。因为它现在不比所有其他剩余物品(&lt; 3,3&gt;)更昂贵。

简单的贪婪算法可能会失败。设置&lt; 2,1&gt;,&lt; 1,2&gt;,&lt; 3,0&gt;并且初始金币数量= 4,银= 2,最佳解决方案是&lt; 1,2&gt;和&lt; 3,0&gt;,但购买&lt; 2,1&gt;首先导致只能购买该商品(购买时剩下的是&lt; 2,1&gt;硬币,不允许购买剩下的两件商品)。

我会接受这个购买建立部分订单结构然后执行回溯搜索。如果时间限制不允许完全回溯,我会使用有限的回溯作为其他贪心算法的启发式算法。

答案 2 :(得分:-2)

没有“算法”。

您正在描述背包问题的一个版本,这是一个众所周知的NP完全问题。对于问题的小版本,使用小N,M和k,您只需经历所有不同的组合。对于较大的版本,没有已知的方法可以找到一个“最佳”解决方案,该解决方案需要的时间少于宇宙的生命周期才能计算出来。

最接近解决这个问题涉及一个称为线性规划的领域。这不是一件简单的事情,但如果你愿意的话,你可以去阅读它。