这个问题可以用动态规划进行优化吗?

huangapple go评论96阅读模式
英文:

Can this problem be optimized with Dynamic Programming?

问题

以下是您提供的代码的中文翻译部分:

from typing import List

class Solution:
    def getMinimumCost(self, a: List[int], b: List[int], m : int):
        已购物品 = 0 
        最低成本 = 0
        映射键 = [i  for i in range(len(a))]
        映射值 = [0 for i in range(len(a))]
        物品 = dict(zip(映射键, 映射值))
        print(物品)

        while 已购物品 < m: 
            成本 = [a[i] + (物品[i] + 1 - 1) * b[i]  for i in range(len(a)) ]
            成本.sort()
            forin 物品:
                物品[键] = 物品[键] + 1
            
            for cost in 成本: 
                最低成本 += cost 
                已购物品 += 1 

                if 已购物品 == m:
                    break

        return 最低成本

if __name__ == "__main__"   :
    sol = Solution()
    最小成本 = sol.getMinimumCost([4, 1], [1, 3], 3)
    print("购买 {} 件物品的最小成本是 {}".format(3, 最小成本))

请注意,我已经将代码中的注释和变量名进行了翻译,以使其更容易理解。如果您有其他需要,请随时告诉我。

英文:

I have a problem that seems a dynamic programming one. I started learning about DP a few days ago and I'm stuck.

Definition

In a store, there are n items, each associated with two positive values a[i] and b[i]. There are infinitely many items of each type numbered from 1 to infinity and the item numbered j of type i costs a[i] + (j - 1) * b[i] units.

Determine the minimum possible cost to purchase exactly m items.

Constraints

1 &lt;= n &lt;= 10^5

1 &lt;= a[i],b[i] &lt;= 10^5

1 &lt;= m &lt;= 10^5

Example

Given n = 3, a = [2, 1, 1], b = [1, 2, 3], m = 4

The optimal types to buy are:

  • Choose i = 1. This is the first purchase of this type of item, so j = 1.The first item costs a[1] + (1 - 1) * b[i] = 1 + (1 - 1) * 2 = 1.
  • Choose i = 2. Again, it is the first purchase of this type so j = 1.The second item costs 1 + (1 - 1) * 3 = 1
  • Choose i = 0 which costs 2 + (1 - 1) * 1 = 2
  • When a second unit of any type is purchased, j = 2 for that transaction. The costs of a second units of each item are:
    • a[0] costs a[0] + (2 - 1) * b[0] = 2 + 1 * 1 = 3

    • a[1] costs 1 + 1 * 2 = 3

    • a[2] costs 1 + 1 * 3 = 4

    • Choose either a[0] or a[1] since they cost less.

The total cost to purchase is 1 + 1 + 2 + 3 = 7.

Function Description

The function getMinimumCost takes three parameters: a is a costs integer array, b is a costs integer array and m is the items to be purchased. It returns a long integer: the minimum cost.

This is my attempt so far:

from typing import List

class Solution: 
    def getMinimumCost(self, a: List[int], b: List[int], m : int):
        buyed_items = 0 
        minimum_cost = 0
        map_keys = [i  for i in range(len(a))]
        map_values = [0 for i in range(len(a))]
        items = dict(zip(map_keys, map_values))
        print(items)

        while buyed_items &lt; m: 
            costs = [a[i] + (items[i] +1 - 1) * b[i]  for i in range(len(a)) ]
            costs.sort()
            for key in items:
                items[key] = items[key] + 1
            

            for cost in costs: 
                minimum_cost += cost 
                buyed_items += 1 

                if buyed_items == m:
                    break

        return minimum_cost

if __name__ == &quot;__main__&quot;   :
    sol = Solution()
    min_cost = sol.getMinimumCost([4, 1], [1, 3], 3)
    print(&quot;min cost to buy {} items is {}&quot;.format(3, min_cost))

答案1

得分: 2

以下是您要翻译的内容:

"The main issue in your attempt is that it takes one of each item type in each iteration of the outer loop, thereby taking an equal number of each until the required amount is reached, so that the final solution will have taken some 𝒘 items of type 1...𝒙 and (𝒘−1) of item types (𝒙+1)...𝒚. But the best solution could consist of taking completely different counts of items depending on the item type.

For instance, take this run:

a = [2, 10]
b = [2,  1]
min_cost = sol.getMinimumCost(a, b, 6)

The solution is to take 5 times the first item type (costs are 2, 4, 6, 8, 10) and once the second item type (cost is 10). The total minimal cost is then 40. Your code will return 45, because it takes 3 of each (costs are 2, 4, 6 for the first type, and 10, 11, 12 for the second).

Algorithm

No dynamic programming is needed.

I would suggest an algorithm where you only take one item per iteration of the outer loop, the cheapest one. To determine which is the cheapest one, sort is not very efficient, as that would have a time complexity of O(𝒚log𝒚) per call, giving a total time complexity of O(𝒙𝒚log𝒚).

It will be more efficient to maintain a min-heap populated with all item types, from which you extract the cheapest and push back that same item type with its updated price (so it can contend with the other prices). This pop/push operation has a time complexity of O(log𝒚), giving a total time complexity of O(𝒙log𝒚).

Implementation

from heapq import heapify, heapreplace

class Solution: 
    def getMinimumCost(self, a: List[int], b: List[int], m : int):
        priceheap = list(zip(a, b))  # (price, increase) tuples
        heapify(priceheap)  # from now on its a minheap

        minimum_cost = 0
        for _ in range(m):
            price, increase = priceheap[0]  # cheapest
            # increase price of the selected item for next time:
            heapreplace(priceheap, (price + increase, increase))
            minimum_cost += price

        return minimum_cost
英文:

The main issue in your attempt is that it takes one of each item type in each iteration of the outer loop, thereby taking an equal number of each until the required amount is reached, so that the final solution will have taken some 𝑘 items of type 1...𝑥 and (𝑘−1) of item types (𝑥+1)...𝑛. But the best solution could consist of taking completely different counts of items depending on the item type.

For instance, take this run:

a = [2, 10]
b = [2,  1]
min_cost = sol.getMinimumCost(a, b, 6)

The solution is to take 5 times the first item type (costs are 2, 4, 6, 8, 10) and once the second item type (cost is 10). The total minimal cost is then 40. Your code will return 45, because it takes 3 of each (costs are 2, 4, 6 for the first type, and 10, 11, 12 for the second).

Algorithm

No dynamic programming is needed.

I would suggest an algorithm where you only take one item per iteration of the outer loop, the cheapest one. To determine which is the cheapest one, sort is not very efficient, as that would have a time complexity of O(𝑛log𝑛) per call, giving a total time complexity of O(𝑚𝑛log𝑛).

It will be more efficient to maintain a min-heap populated with all item types, from which you extract the cheapest and push back that same item type with its updated price (so it can contend with the other prices). This pop/push operation has a time complexity of O(log𝑛), giving a total time complexity of O(𝑚log𝑛).

Implementation

from heapq import heapify, heapreplace

class Solution: 
    def getMinimumCost(self, a: List[int], b: List[int], m : int):
        priceheap = list(zip(a, b))  # (price, increase) tuples
        heapify(priceheap)  # from now on its a minheap

        minimum_cost = 0
        for _ in range(m):
            price, increase = priceheap[0]  # cheapest
            # increase price of the selected item for next time:
            heapreplace(priceheap, (price + increase, increase))
            minimum_cost += price

        return minimum_cost

huangapple
  • 本文由 发表于 2023年6月26日 16:28:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76554893.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定