选择最低成本的组合

Posted

技术标签:

【中文标题】选择最低成本的组合【英文标题】:Selecting A combination of minimum cost 【发布时间】:2014-02-21 00:45:26 【问题描述】:

我有不同餐厅不同项目的数据

    Rest    Item     Price
    ----------------------
    ABC     dosa      14
    ABC     idly      30
    ABC     idly+upma 25

    123     dosa      30
    123     idly      7
    123     upma      12

    XYZ     dosa      20
    XYZ     idly      12
    XYZ     upma      20
    XYZ     dosa+upma 30
    XYZ     dosa+idly+upma 40

Now I need to pickup a restaurant which gives me the best deal of "dosa+idly+upma" items.

从上面的例子:它将是餐厅“ABC”

我无法设计有效的方法来做到这一点,或者不知道该怎么做?有什么想法吗?

更新

这是我的对象的样子

Class Rest
  Map<String,Integer> menu; //item,price map

【问题讨论】:

dosa+idly+upma ABC 价格为 39 卢比 ?? 给我们一些限制。输入的大小是多少?您希望搜索多少个项目?有多少项目?有多少家餐厅? @amit,这是样本数据。预计它会节省时间。数据没有太多限制。 @Reddy 那么规模是多少?许多?数百?数千?百万?如果它只有几十个 - 不要费心优化它。如果是数百万 - 那么,情况就完全不同了。 您的意思是您需要所有 3 件商品的最优最高价格,还是一件商品的价格比另一件更重要(例如,便宜的 dosa 比便宜的 upma 更重要)?我也饿了。 【参考方案1】:

一种可能的贪婪算法的草图是:

    遍历所有一元报价(例如 dosaidlyupma)以找到每个报价的最小值。 遍历所有 binaray(例如 idly+upma)/三级 (...) 报价,比较它是否比一元报价便宜,如果是则替换。

您仍然需要对报价进行编码,但应该不会那么难。该算法会找到好的但不是必需的最佳解决方案,并且可能适用于非常小的样本。

实际上,您的问题与 背包或 TSP 问题相比,它们是 NP 完全的,因此只能在指数时间内解决。如果您想要一个解决方案,请考虑阅读大量论文并进行更多编码。这就是计算机科学的圣杯。 ;-)

更新:根据 TO 的要求,这里有一些指数伪代码草图:

foreach restaurant
    create a list of all possible combinations of the offers // here's the exp!
    filter those combinations that hold more/less than 1 dosy/idly/umpa
    select minimum of the remaining ones

评论:这真的很丑,yuk! :-(

【讨论】:

必须有一个更有效的解决方案,然后对每个查询强制使用整个数据库... @LastFreeNickname,因为我不关注大规模数据,而且我知道它是长数据的 NP 问题,或者它不会处理大数据。对于这个简单的数据,假设我的餐厅不超过 5 家,每家餐厅的商品不超过 10 家。 @Reddy 那么你唯一的可能就是按照上面的解释强行使用它,并希望你的数据永远不会变大。 :-) 你可能会考虑一种比我更脏的方法来保持你的算法简单。【参考方案2】:

    计算可能的价格组合:遍历地图并解析字符串。存储每个价格组合。

    过滤掉更贵的价格。

    比较每家餐厅的剩余价格,返回价格最低的餐厅。

您还可以进行一些检查以最小化迭代,例如:

如果 idly 大于 idly+umpa,则不计算任何涉及 idly 的组合。

【讨论】:

第一次也是这么想的,但是一旦您在这种方法中包含 >= 1 个商品,比较的顺序就会改变结果。说:idly+upma 可能会阻止 dosa+idly 替换,反之亦然。请参阅我的帖子以获取更多说明。 @LastFreeNickname 我不确定我是否理解你。您指的是第 2 步吗? 如果我理解线程开启器,任务也是用min_upmaidly替换min_upma和min_idly。这部分它丢失了。【参考方案3】:

首先,您需要将 3 个项目的所有可能组合与不同的餐厅相对应,例如:

XYZ     dosa+idly+upma 52
XYZ     dosa+upma+idly 42
XYZ     dosa+idly+upma 40

所有餐厅的情况都一样。

然后对价格进行排序,让最低价格重新获胜。

【讨论】:

假设 3 只是一个示例,您可能在一家餐厅有更多商品,而您只会要求其中的一部分 - 这种方法需要为每个餐厅创建 2^n 不同的集合,其中 @如果您想在预处理中进行,987654323@ 是元素的总数。 @amit 根据要求,我已经提供了答案。 要求没有说 3 项。这个例子做了。 我怎么知道它的例子或要求?如果您想缩放项目,那么您也需要使用相同的逻辑。【参考方案4】:

这个问题是NP-Hard。我将展示从Set Cover Problem 减少的内容。

设置掩护问题 (SCP): 给定一组元素U(在您的示例中为U=dosa,idly,upma)和一组U 的子集,让它成为S(例如S=dosa, idly,upma, upma)找到最少数量的@ 子集987654328@ 使得它们的并集等于U

减少: 给定US 的集合封面问题,创建一个关于一家餐厅的问题实例,使得S 中每个项目的价格(这是一个集合一项或多项)为 1。

现在,给定您问题的最佳解决方案 - 可能的最低价格,基本上是覆盖“宇宙”所需的最小子集数量。 给定集合覆盖问题的最优解 - 所需集合的数量是子集的最低价格。

结论: 由于我们已经看到有效地解决这个问题将有效地解决 SCP,我们可以得出结论,该问题是 NP-Hard,因此没有已知的多项式解决方案(并且大多数人认为不存在)。

替代方案是使用启发式解决方案或蛮力解决方案(只需搜索所有可能性,在指数时间内)。

【讨论】:

我就是这么说的。 :-) 虽然我将它与同级别的背包和 TSP 进行了比较。 @LastFreeNickname 是的,我看到你现在做到了。但我添加了一个正式的证明——我认为它有附加价值,你不是说吗?【参考方案5】:

试试

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Mult 
    /**
     * @param args
     */
    public static void main(String[] args) 
        Map<String,List<X>> xx = new HashMap<String,List<X>>();
        xx.put("ABC",new ArrayList<X>());
        xx.get("ABC").add(new X("", 0));
        xx.get("ABC").add(new X("dosa", 14));
        xx.get("ABC").add(new X("idly", 30));
        xx.get("ABC").add(new X("idly+upma", 25));


        xx.put("123",new ArrayList<X>());
        xx.get("123").add(new X("", 0));
        xx.get("123").add(new X("dosa", 30));
        xx.get("123").add(new X("idly", 7));
        xx.get("123").add(new X("upma", 12));


        xx.put("XYZ",new ArrayList<X>());
        xx.get("XYZ").add(new X("", 0));
        xx.get("XYZ").add(new X("dosa", 20));
        xx.get("XYZ").add(new X("idly", 12));
        xx.get("XYZ").add(new X("upma", 20));
        xx.get("XYZ").add(new X("dosa+upma", 30));
        xx.get("XYZ").add(new X("dosa+idly+upma", 40));

        String[] t = 
                "dosaidlyupma",
                "idlydosaupma",
                "upmaidlydosa",
                "dosaupmaidly",
                "upmadosaidly",
                "idlyupmadosa";
        Set<String> targets = new HashSet<String>(Arrays.asList(t));

        Map<String,Integer> best = new HashMap<String,Integer>();

        for(String restaurant:xx.keySet())
            best.put(restaurant, Integer.MAX_VALUE);
            String combo = null;
            for(X a:xx.get(restaurant))
                int deal = a.price;
                combo = a.item;
                for(X b:xx.get(restaurant))
                    deal = deal + b.price;
                    combo = combo + "+" + b.item;
                    for(X c:xx.get(restaurant))
                        deal = deal + c.price;
                        combo = combo + "+" + c.item;
                        if (targets.contains(combo.replaceAll("\\+", "")))
//                          System.out.println(restaurant+"\t"+combo.replaceAll("\\+", "")+"\t"+deal);
                            if (best.get(restaurant) > deal)
                                best.put(restaurant, deal);                 
                            
                        
                    
                
            
        

        System.out.println(best);
    


会给你

XYZ=40, ABC=39, 123=49

这是旧的蛮力方法。

不是最好的,但对于这个小套装,它可以工作。

【讨论】:

以上是关于选择最低成本的组合的主要内容,如果未能解决你的问题,请参考以下文章

经管-8

尽管成本低、基数低,但 Oracle 中的选择查询需要很长时间

Chia奇亚币硬盘挖矿,门槛低成本并不低,玩家入坑需谨慎

服务器硬件选择

正鑫网络:低成本创业项目

搭建一个网站最低需要多少钱?如何以最低成本做一个网站?