查找覆盖项目列表所需的最小容器数的算法

时间:2019-04-25 10:26:59

标签: algorithm optimization

我遇到的问题并非特定于任何语言或框架,它更像是算法问题:

我有一个包含各种物品的“容器”列表。容器中包含的每个项目都有数量和类型,因此,一个容器中可能有3个苹果和2个桃子,另一个容器中有12个桃子,而另一个容器有5个梨。

我必须想出一种算法,该算法接受此信息以及一个请求,并返回可以满足该请求的最小数量的容器。该请求本质上是所需物品清单以及所需数量,将其视为购物清单。

因此,根据我上面给出的示例:

Container A:
    3 x apple
    2 x peach

Container B:
    12 x peach

Container C:
    5 x pear

和此请求

I want:
    1 x apple
    6 x peach

算法应该告诉我,满足此请求的最佳方法是同时使用容器A和B,并且从A消耗1个苹果和2个桃子,从B消耗4个桃子(或者可能所有6个桃子都是从B和A消耗的糖仅用于苹果,这没关系)。

该算法还应能够根据可用容器判断何时无法满足请求(例如:无法满足35个西瓜的请求),并在可能时为不同容器赋予不同的优先级(例如:与其他内容非常相似的容器相比,交付速度更快的容器应该会有所提升,但是要迅速交付给客户则更加困难。)

到目前为止,我已经尝试使用一种非常琐碎且有点kind脚的评分算法(伪代码):

itemsLeft = copy(itemsInRequest)
containersLeft = copy(containers)
choosenContainers = []

while len(itemsLeft) > 0:
    if len(containersLeft) == 0:
        return Error("No more containers, can't satisfy request")
    bestScore = 0
    bestContainer = null
    foreach container in containersLeft:
        // Give a score based on the items it contains
        score = 0
        foreach item in itemsLeft:
            if container.contains(item.type):
                score += min(container.quantityOf(item.type), item.wantedQty)
        // Take priority into account
        score += container.priority
        if score > bestScore:
            bestScore = score
            bestContainer = container
    choosenContainers.append(bestContainer)
    containersLeft.remove(bestContainer)
    foreach item in itemsLeft:
        if bestContainer.contains(item.type):
            quantityInContainer = bestContainer.quantityOf(item.type)
            // This will consume items in itemsLeft, eventually
            // removing them from the list if the quantity
            // reaches 0
            item.consume(quantityInContainer)
return choosenContainers

但是我对此并不十分满意,因为我认为它不是经过深思熟虑和高效能的,但是目前我无法提出更好的建议。

我也不认为它能很好地处理边缘情况。例如:假设一个请求不能用可用的容器满足。该算法将选择所有容器而实际上并没有实现任何目标,只是因为优先级会给它们一些非零的分数。

我在想,也许我可以通过一些我不知道的,已经存在的,经过验证的算法来实现类似的目标?

您能推荐解决此类问题的任何算法还是类似算法,以便我从中汲取灵感,或者就如何解决此问题给出一些建议?

2 个答案:

答案 0 :(得分:0)

首先,您的解决方案还有一个问题,那就是优化不佳/无法处理不可能的情况。

例如,对于这个测试用例:

Container A:
    10 apples
Container B:
    5 apples
    1 pear
Container C:
    5 apples
    1 pear
Request:
    10 apples
    2 pears

您的代码将返回3个容器(容器A在第1次迭代中得分最高)。

有一种简单的方法可以给出正确的结果,但是具有指数级的复杂性:

resultContainers = None
resultNumberContainers = inf
for each binary_mask in range(0, pow(2,containerLength)):
    actContainer = emptyContainer
    numberContainers = 0
    for each i in range(0,containerLength):
        if(pow(2,i) & binary_mask):
            actContainer = actContainer + containers[i]
            numberContainers += 1
    if(ok(actContainer) && numberContainers < resultNumberContainers):
        resultNumberContainers = numberContainers
        resultContainers = actContainer

答案 1 :(得分:0)

这个问题可以通过查看每个容器并确定是否包含(获取)容器 i 来解决。

因此,我们一个接一个地遍历所有容器,对于每个容器,我们看起来有两种选择:  1. 包含容器  2. 排除容器

我们以递归方式进行此调用。在每个调用中,如果要包含容器,则需要增加#of Containers。同时减少剩余商品的数量。

我们会一直这样做,直到遇到没有剩余容器或满足所有要求的物品的情况。 然后,我们取所有看到的值的 min