【问题标题】:Algorithm - generating all combinations from items that must be chosen in sequence算法 - 从必须按顺序选择的项目中生成所有组合
【发布时间】:2011-12-31 21:07:55
【问题描述】:

我正在寻找是否已经存在特定算法。 我想在应用程序中使用它,但我也看到这出现在几个Project Euler 问题中。

我正在寻找一种特定类型的排列/输出集,其中选择的下一个项目必须是仅在以下集合中的有限选项集中的一个。

例如,假设我有 3 个数组

$a1 = array("a", "b", "c");
$a2 = array("d", "e", "f");
$a3 = array("g", "h", "i");

我希望生成一个序列的所有可能性,该序列包含每个数组中最多 1 个元素按顺序选择。也就是说作为输出,我想看看:

adg aeg afg
adh aeh afh
adi aei afi

bdg beg bfg 
bdh beh bfh
bdi bei bfi

cdg ceg cfg
cdh ceh cfh
cdi cei cfi

希望在 PHP 或 Javascript 中实现该算法。本质上,它将遍历包含可变数量元素的可变数量的数组,并输出可以按顺序出现的所有可能的序列。

这存在吗?

如果是这样,它叫什么?从技术上讲,这不是我对两者的了解的排列或组合。

编辑:Daniel Fischer 告诉我这是一个笛卡尔积,这是一个实现taken from the PHP website

function array_cartesian_product($arrays)
{
    $result = array();
    $arrays = array_values($arrays);
    $sizeIn = sizeof($arrays);
    $size = $sizeIn > 0 ? 1 : 0;
    foreach ($arrays as $array)
        $size = $size * sizeof($array);
    for ($i = 0; $i < $size; $i ++)
    {
        $result[$i] = array();
        for ($j = 0; $j < $sizeIn; $j ++)
            array_push($result[$i], current($arrays[$j]));
        for ($j = ($sizeIn -1); $j >= 0; $j --)
        {
            if (next($arrays[$j]))
                break;
            elseif (isset ($arrays[$j]))
                reset($arrays[$j]);
        }
    }
    return $result;
}

【问题讨论】:

    标签: algorithm theory combinatorics


    【解决方案1】:

    这是一个笛卡尔积,如果从每个列表/数组中恰好选择一个项目,更准确地说是笛卡尔积的元素列表。对于列表,它在 Haskell 的标准库中:

    Prelude> sequence ["abc","def","ghi"]
    ["adg","adh","adi","aeg","aeh","aei","afg","afh","afi","bdg","bdh","bdi","beg","beh"
    ,"bei","bfg","bfh","bfi","cdg","cdh","cdi","ceg","ceh","cei","cfg","cfh","cfi"]
    

    我认为对于 PHP 或 Javascript,您必须自己编写代码。

    【讨论】:

      【解决方案2】:

      您可以循环遍历元素。例如,您可以针对您的案例执行以下操作:

      var ret = [];
      for (var i=0; i<a1.length; i++) {
        for (var j=0; j<a2.length; j++) {
          for (var k=0; k<a3.length; k++) {
            ret.push( [a1[i], a2[j], a3[k]] );
          }
        }
      }
      // do stuff with ret
      

      请注意,这很慢,尤其是当您有很多非常长的数组时。对于 Project Euler,您通常可以使用其他一些见解来代替枚举所有内容。

      【讨论】:

      • 对,但是我希望抽象出这个概念,以便我可以针对可变数量的数组运行它。
      【解决方案3】:

      我认为你是对的,它既不是排列也不是组合,因为字符串长度在你的情况下是固定的。请原谅我使用 java [7],但这是我目前最了解的。

      public abstract class AFixedPermutation {
         private char[][] fields;
         private StringBuilder sb = new StringBuilder();
         private int[] callvec;
         private int maxDepth;
      
         public FixedPermutation(char[][] fields) { 
           this.fields = fields; 
      
           callvec = new int[fields.length];
           for (int i = 0; i < fields.length; i++) callvec[i] = 0;
           maxDepth = callvec.length - 1;
           recurse(0);
         }
      
         protected abstract emit(String s);
      
         private void recurse(int depth) {
           for (int i = 0; i < fields[depth].length; i++) { 
              callvec[depth] = i;
              if (depth == maxDepth) { apply(); }
              else {recurse(depth + 1); }
           }
         }
      
         private void apply() {
            sb.setLength(0);
            for (int i = 0; i < callvec.length; i++) {
              sb.append(fields[i][callvec[i]]);
            }
            emit(sb.toString());
         }
      }
      

      【讨论】:

        【解决方案4】:

        Mathematica 中,本机实现为 Tuples

        Tuples[{{a, b, c}, {d, e, f}, {g, h, i}}]
        
        {{a, d, g}, {a, d, h}, {a, d, i}, {a, e, g}, {a, e, h}, {a, e, i },
         {a, f, g}, {a, f, h}, {a, f, i}, {b, d, g}, {b, d, h}, {b, d, i},
         {b, e, g}, {b, e, h}, {b, e, i}, {b, f, g}, {b, f, h}, {b, f, i},
         {c, d, g}, {c, d, h}, {c, d, i}, {c, e, g}, {c, e, h}, {c, e, i},
         {c, f, g}, {c, f, h}, {c, f, i}}

        也可以用Outer(广义外积):

        Outer[List, {a, b, c}, {d, e, f}, {g, h, i}]
        

        或使用迭代 (Table):

        Table[{x, y, z},
         {x, {a, b, c}},
         {y, {d, e, f}},
         {z, {g, h, i}}
        ]
        

        或者使用递归:

        sets[{}, c__] := {{c}}
        sets[{x_, r___}, c___] := Join @@ (sets[{r}, c, #] & /@ x)
        
        sets[{{a, b, c}, {d, e, f}, {g, h, i}}]
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-07-15
          • 1970-01-01
          • 2015-01-23
          • 1970-01-01
          • 2020-02-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多