代码之家  ›  专栏  ›  技术社区  ›  Adam Davis

复杂组合算法

  •  17
  • Adam Davis  · 技术社区  · 16 年前

    因此Wendy's广告他们的三明治有256种成分组合——这意味着有8种成分你可以不吃(虽然我想知道为什么他们会把没有任何有效成分的成分组合计算在内,但我离题了)。

    这些都相当简单。将选项的数量相乘,因此对于Wendy的:

    如果他们像上面那样多样化选择芥末,那将是:

    2*2*3*2*2*2*2*2 = 384

    走得更远似乎更难。

    如果你把芝麻单独做一个项目,那么他们需要的面包项目。你可以只吃芝麻,如果你包括了面包,你可以吃没有芝麻的面包,但是你不能吃没有面包的芝麻。这可以简化为具有三种状态(无、带种子的面包、不带种子的面包)的单个面包项目,但在某些情况下无法做到这一点。

    例如,戴尔的计算机配置程序不允许某些组合(可能插槽都满了,项目放入同一系统时不兼容,等等)。

    • 在处理项目可能发生冲突的更复杂系统时,适当的组合方法是什么?
    • 什么是好的、通用的方法来存储这些信息,而不必为每个产品/组合/项目编写代码来捕捉冲突?
    • 当系统必须处理复杂的冲突组合时,有没有一种简单的方法可以说“有X种方法可以配置您的系统/三明治”?
    8 回复  |  直到 12 年前
        1
  •  3
  •   Community Mohan Dere    5 年前

    定义零件&产品(预编码)

    定义所有“零件”时,最重要的是确定零件的层次结构和分类。这是真的,因为某些规则可能是唯一部分所独有的 ,一些分类的 (例如“所有野马”) ,有些按类型分类 (例如“所有调味品”)

    生成规则集(预编码)

    为每个独特的零件、类别、类型和成品定义规则集(先决条件、排除项等)。

    这听起来可能有点傻,但必须非常小心,以确保规则的定义具有适当的范围。例如,如果成品是 Burger :

    • 唯一项规则- “蘑菇只可搭配精选的蓝奶酪” prerequisite
    • 分类规则- “只能选择1个芥末” exclusive
    • 类型规则- “泡菜和辣椒不相容” 独家

    在花了太多时间研究“零件”的独特/类别/类型规则之后,许多设计师将忽略仅适用于成品的规则,即使零件没有冲突。

    • “最多5种调味品” condition
    • “汉堡必须有个小面包”

    这个规则图可能很快变得非常复杂。

    关于构建数据结构(规范)的建议

    1. 仔细选择继承建模(基类)和对象属性(例如。 Category HasCondiments (国旗)使这项工作。

    2. 制造 对于 RuleSets 在每个层次对象级别。

    3. 制作 公共财产 暂时 HasConflicts 国旗,和 RuleViolations 收集

    4. 将零件添加到产品中时,请检查所有级别的规则(其自身的、类别、类型和产品)——通过 公共职能 可以从产品中调用。或者为了更好的内化,你可以 就这一部分而言。

    编写你的算法(代码)

    这一步的诀窍是如何在代码中实现沿树/图向上移动的规则——例如,当一个特定部分与其范围外的另一个部分发生问题时,或者当添加另一个部分时,如何运行其验证?我的想法是:

    1. 使用 CurrentParts 收集

    2. 在产品对象上,定义要处理的处理程序 OnPartAdded OnPartRemoved ,并让他们列举 当前部件 收集并调用每个部件的验证函数。

    裸骨原型示例

    interface IProduct
    {
        void AddPart();
        void OnAddPart();
    }
    // base class for products
    public class Product() : IProduct
    {
         // private or no setter. write functions as you like to add/remove parts.
        public ICollection<Part> CurrentParts { get; };
        // Add part function adds to collection and triggers a handler.
        public void AddPart(Part p)
        {
            CurrentParts.Add(p);
            OnAddParts();
        }
        // handler for adding a part should trigger part validations
        public void OnAddPart()
        {
            // validate part-scope rules, you'll want to return some message/exception
            foreach(var part in CurrentParts) {
                part.ValidateRules(CurrentParts); 
            }
            ValidateRules(); // validate Product-scope rules.
        }
    }
    
    interface IProduct
    {
        // "object" should be replaced with whatever way you implement your rules
        void object RuleSet; 
        void ValidateRules(ICollection<Part> otherParts);
    }
    // base class for parts
    public class Part : IPart
    {
        public object RuleSet; // see note in interface.
    
        public ValidateRules(ICollection<Part> otherParts)
        {
            // insert your algorithms here for validating 
            // the product parts against this part's rule set.
        }
    }
    

    又好又干净。

        2
  •  5
  •   iokevins    16 年前

    工厂车间构建周期过程包括预先检查,以确保订单在发布给构建者和测试者之前是可构建的。

    其中一项检查确定订单的物料清单(BOM)是否符合工艺工程师指定的规则列表。例如,如果客户订购处理器,确保他们也订购了足够的直流转换器零件;或者,如果他们订购了一定数量的内存DIMM,请确保他们还订购了子板以容纳额外的容量。

    作为一个副作用,该系统还为每个订单生成了构建文档,工人在构建每个系统时会提取这些文档。它还生成了构建后老化过程的预期测试结果,以便测试间隔可以引用它们并确定是否所有内容都正确构建。

        3
  •  4
  •   Community Mohan Dere    5 年前

    亚当·戴维斯 :如果我理解正确,您打算开发某种系统,实际上可以用于购物车,帮助用户购买兼容部件。

    问题定义

    这是一个图形问题( Pentium i3-2020 与任何 Socket 1155 Motherboard Asrock H61M-VS 是一个 插座1155主板 PCI-Express GPU , DDR3 PC RAM{Total(size) <= 16GB} 4 pin ATX 12V power

    您需要能够(a)确定篮子中的每个项目是否满足篮子中另一个项目的要求(即RAM卡具有兼容的主板),(b)分配最合适的项目(即,如果主板的USB端口用完,将USB集线器分配给主板USB端口,将打印机分配给USB集线器,(c)为用户提供一个功能来查找满意的组件列表。也许USB集线器作为扩展总是可以优先使用(但一定要注意)。

    您将需要的数据结构

    您需要一个简单的分类系统,即H61M-VS is-a 有一个 DDR3 内存插槽(每个插槽具有速度属性)。

    其次是分类和组合,您需要识别需求,这非常简单。现在,简单分类可以允许一个简单的SQL查询找到符合分类的所有项。

    测试一个令人满意的篮子

    要测试篮子,需要创建一个配置,确定与哪个项目匹配(即主板的DDR3插槽与4GB Ram模块匹配,SATA HDD电缆连接到主板SATA端口和PSU的SATA电源电缆,而PSU的4针ATX 12V电源电缆连接到主板)。

    最简单的事情就是检查是否存在另一个令人满意的项目

    戴尔电脑配置器

    你从一个项目开始,比如说处理器。处理器需要一块主板和一个风扇,因此您可以给它们选择主板(将处理器风扇添加到 list_of_things_to_be_satisfied ). 此操作将继续,直到中不再保留任何项目 . 当然,这一切都取决于你的 而且知道 什么问题 您将为用户解决问题。

        4
  •  2
  •   Guillermo Phillips    16 年前

    作为一名程序员,我会做以下工作(尽管我在现实生活中从来没有这样做过):

    • 算出总数 组合,通常是直的 期权的乘法 在你的问题中陈述就足够了。 组合。
    • 例外情况。例外情况可以是 有效地说出哪些组合
    • 算出总数 如果允许,您将拥有 浏览整个

    如果将所有组合视为一个集合,那么异常只会删除该集合的成员。但是您不需要存储整个集合,只需要存储异常,因为您可以计算 大小 这一套很简单。

        5
  •  2
  •   JB King    16 年前

    " Generating Functions “在解决这类问题时,作为一种结构出现在脑海中。我要注意的是,有几个不同的生成函数取决于你想要什么。

    在北美,汽车牌照在计算所有排列时可能是一个有趣的组合问题,其中6或7的每个位置都有36个可能的值,这些值是车牌的长度,取决于获得车牌的位置。然而,有些组合是不合格的,因为其中一些组合中有脏话或种族主义词语,这使得问题稍微难一些。例如,有一个infamour N-word,它至少有两种不同的拼写,我认为这是不允许出现在车牌上的。

    另一个例子是使用一个给定的字母表来确定单词的所有不同顺序,该字母表包含一些重复多次的项目。例如,如果一个人想要所有不同的方式来排列字母,就说“字母”这个词,它不仅仅是6个!这就是“abcdef”的情况,因为有两对字母,计算起来稍微有点困难。

    L33t

        6
  •  1
  •   Brienne Schroth    16 年前

    您可能希望创建一个唯一表示单个配置的数据结构。然后,应以一种方式定义每个兼容性规则,使其能够生成一个包含所有未通过该规则的单个配置的集合。然后,您将使用所有规则生成的所有集合的并集来获得所有不符合规则的配置的集合。然后计算该集合的大小,并从集合的大小中减去所有可能的配置。

    最困难的部分是定义数据结构的方式可以由您的规则生成,并且可以让集合操作在其上工作!这是给读者的练习,我什么都没有。

        7
  •  1
  •   MahdeTo Ben ODay    14 年前

    我现在唯一能想到的就是构建,如果你能构建一棵树,定义你有一个简单解决方案的部分之间的依赖关系。

    sandwitch
    |
    |__Bun(2)__sesame(1)
    |
    |__Mustard(3)
    |
    |__Mayo(2)
    |
    |__Ketchup(2)
    |
    |__Olives(3)
    

    这简单地说,你有2个面包选择(面包或没有面包),1个芝麻(只有当你有一个面包-表示依赖-如果你有一个7在这里它意味着7种类型,可以存在,如果你只有一个面包)

    芥末酱3英镑。。等

        8
  •  1
  •   hpixel    14 年前

    也许可以将问题形式化为一个问题 k-sat problem . 在某些情况下,问题看起来是NP完全的,你必须列举所有的可能性来检查它们是否满足所有的条件。在其他一些情况下,问题将很容易解决(例如,当需要很少的条件时)。这是一个活跃的研究领域。你可以在谷歌学者网站上找到相关的参考资料。

    对于芥末,您将为芥末类型添加一个二进制条目“芥末类型”,并引入以下条件: not (not mustard and mustard_type) 哪里 mustard 是芥末的二进制条目。它将强制执行默认选择 mustard_type == 0 当你选择 not mustard

    对于芝麻选择,这一点更加明确: not (sesame and not bun) .

    因此,您提出的案例似乎属于2-sat系列问题。

    推荐文章