生成所有可能的组合

Posted

技术标签:

【中文标题】生成所有可能的组合【英文标题】:Generate all possible combinations 【发布时间】:2016-01-07 18:20:53 【问题描述】:

我有一个应用程序,用户可以通过从菜单中选择选项来自定义他们要购买的产品。这个菜单有很多部分,每个部分可能有一个多选复选框列表,或者当只能选择一个选项时的单选按钮。用户必须在每个部分中至少选择一个选项。菜单结构是这样的:

$sections = array();

$sections[1] = array(
    'multichoice' => true,
    'options' => array('A','B','C')
);

$sections[2] = array(
    'multichoice' => false,
    'options' => array('A','B','C','D')
);

$sections[3] = array(
    'multichoice' => false,
    'options' => array('A','B')
);

$sections[4] = array(
    'multichoice' => true,
    'options' => array('A','B','C','D','E')
);

示例:三明治是产品。面包的类型是选择的一个“部分”。您可能想要清淡面包、黑面包、牛奶面包或纯素面包。在此部分下只能选择一个选项。现在在“沙拉”部分,您可以选择不止一种沙拉添加到面包中。

现在,我的老板要求我创建一个页面,列出所有可能的组合,以防用户懒得自己构建产品。所以我必须能够生成这样的结构:

$combinations = array(
    array(
        1 => array('A','B'),
        2 => 'A',
        3 => 'A',
        4 => array('B','D','E')
    ),
    array(
        1 => array('A'),
        2 => 'B',
        3 => 'A',
        4 => array('A','B')
    )
// etc...
);

我已经设法使用随机方法找到所有可能的组合,生成哈希以与已经生成的内容进行比较。这实际上有效,但运行速度非常慢(这基本上是蛮力):

...

function generate()
    $result = array();
    $ids = array();
    foreach($this->getSections() as $sect)
        $items = $this->getSectionOptions($sect['id']);
        if($sect['multi']=='N')
            $item = $items[rand(0, count($items)-1)];
            $result[$sect['id']] = $item['id'];
            $ids[] = $item['id'];
         else 
            $how_many = rand(1,count($items));
            shuffle($items);
            for($i=1;$i<=$how_many;$i++)
                $item = array_shift($items);
                $result[$sect['id']][] = $item['id'];
                $ids[] = $item['id'];
            
        
    
    sort($ids);
    return array(
        'hash' => implode(',',$ids),
        'items' => $result
    );


function generateMany($attempts=1000)
    $result = array();
    $hashes = array();
    for($i=1;$i<=$attempts;$i++)
        $combine = $this->generate();
        if(!in_array($combine['hash'],$hashes))
            $result[] = $combine['items'];
            $hashes[] = $combine['hash'];
        
    
    return $result;



...

我希望您能帮助我创建更精确、更快的东西。请记住,每个组合必须在每个部分中至少有一个选项。还要记住,多选部分中的选项顺序无关紧要,(即 E,B,A 与 B,E,A 相同)

谢谢

【问题讨论】:

我有点迷茫,你是怎么做出这些组合的? 1) 多选定义了什么? 2) 你能更清楚地解释一下你的组合逻辑吗?我很困惑,对我来说毫无意义 2) 示例:三明治是产品。面包的类型是选择的一个“部分”。您可能想要清淡面包、黑面包、牛奶面包或纯素面包。在此部分下只能选择一个选项。现在在“沙拉”部分,您可以选择不止一种沙拉添加到面包中。我希望能够构建所有可能的三明治。 每个部分是否必须至少有一个选项?...您的示例表明它是。 【参考方案1】:

谢谢,这是一个非常有趣的谜题!

那我是怎么解决的,recursion recursion :D

我从多项选择开始,因为它是最难的! (实际上它也可以解决混合问题)

说明

为了解释我是如何让它工作的,让我们举个例子,选择 A、B、C。然后我们会有以下组合:

A B
A B C
A C
B
B C
C

如果我们仔细观察,我们可以看到一些模式。让我们将结果列表中的第一个元素 (A)

B
B C
C
---
B
B C
C

嗯,有趣...现在让我们再次第一个元素(B)

C
---
C

这是一个简单的案例,但这将发生在任何大小的案例中。

所以我已经制作了递归脚本到最后,然后向后添加迭代组合并与之前的值复制它。

瞧!就是这个!

对于需要所有元素的最终混合,我做了一个非常相似的方法,但它必须每个包含一个元素

而且速度非常快!

126 种组合 100000 次迭代的总时间:14.410287857056 秒

如果你发现任何错误 ping 我 :D

代码

https://gist.github.com/MLoureiro/a0ecd1ef477e08b6b83a

【讨论】:

哇,伙计,你解决了我的问题!!!而且您的解决方案实际上是正确的,因为我的结果是相同数量的组合 (126) 当然,您的解决方案要快得多,我将立即对其进行调整。非常感谢! 前段时间我也写了一个递归算法来解决类似的问题。不同之处在于,我让用户传入输出组合应包含的元素数量(基本上它从输入集 n 中计算大小 r 的所有可能组合)。你可以在这里找到详细的解释:***.com/questions/27308438/…

以上是关于生成所有可能的组合的主要内容,如果未能解决你的问题,请参考以下文章

使用递归和回溯生成所有可能的组合

[Python]:生成所有可能组合的数组

生成所有可能的组合 - Java [重复]

生成所有可能的组合

生成所有可能的组合

生成 0, 1,...n-1, n 个 k 数的所有可能组合。每个组合应按升序排列[重复]