1

長さ X の N 個のセットのすべての可能な組み合わせを重複なしで特定の順序で見つける必要があります。

input:  [["A"], ["B"], ["C"]]
output: [["A","B","C"],["A","B"],["A","C"],["B","C"],["A"],["B"],["C"]]

ルール:

  • パーティションの数またはサイズは固定されていません。
  • 各組み合わせの各パーティションから 1 つのメンバーのみ。
  • より多くのメンバーとの組み合わせが優先されます。
  • 入力の前のメンバーは、後のメンバーよりも優先順位が高くなります。

より大きなセットの別の例:

input:  [["A","B"],["C","D","E"],["F"]]
output: [["A","C","F"],["A","D","F"],["A","E","F"],["B","C","F"],["B","D","F"],["B","E","F"],["A","C"],["A","D"],["A","E"],["B","C"],["B","D"],["B","E"],["A","F"],["B","F"],["C","F"],["D","F"],["E","F"],["A"],["B"],["C"],["D"],["E"],["F"]]

ベキ集合関数の出力をデカルト積関数と組み合わせることで、必要な出力を得ることができましたが、結果のコードはあまり簡潔でもきれいでもありません。これは再帰でもっとうまくできるのではないかと思っていましたか?

これが私がすでに持っているものです:

$test = json_decode('[["A"]]');
$test1 = json_decode('[["A"], ["B"], ["C"]]');
$test2 = json_decode('[["A", "B"], ["C", "D", "E"], ["F"]]');

/**
 * Returns a power set of the input array.
 */                   
function power_set($in, $minLength = 1) {
  $count = count($in);
  $members = pow(2,$count);
  $return = array();

  for ($i = 0; $i < $members; $i++) {
    $b = sprintf("%0".$count."b",$i);
    $out = array();

    for ($j = 0; $j < $count; $j++) {
      if ($b[$j] == '1') {
        $out[] = $in[$j];
      }
    }
    if (count($out) >= $minLength) {
      $return[] = $out;
    }
  }

  return $return;
}

/**
 * Returns the cartesian product of the input arrays.
 */
function array_cartesian() {
  $_ = func_get_args();

  if(count($_) == 0) {
    return array(array());
  }

  $a = array_shift($_);
  $c = call_user_func_array(__FUNCTION__, $_);
  $r = array();

  foreach($a as $v) {
    foreach($c as $p) {
      $r[] = array_merge(array($v), $p);
    }
  }

  return $r;
}

/**
 * Used with usort() to sort arrays by length, desc.
 * If two arrays are the same length, then a sum of 
 * their keys is taken, with lower values coming first.
 */
function arraySizeDesc($a, $b) {
  if(count($a) === count($b)) {
    if(array_sum($a) === array_sum($b)) {
      return 0;
    }

    return (array_sum($a) > array_sum($b)) ? 1 : -1;
  }

  return (count($a) < count($b)) ? 1 : -1;
}

/**
 * Calculates a powerset of the input array and then uses
 * this to generate cartesian products of each combination
 * until all possible combinations are aquired.
 */
function combinations($in) {
 $out = array();
 $powerSet = power_set(array_keys($in));
 usort($powerSet, 'arraySizeDesc');

 foreach($powerSet as $combination) {
   if(count($combination) < 2) {
     foreach($in[$combination[0]] as $value) {
       $out[] = array($value);
     }
   } else {
     $sets = array();

     foreach($combination as $setId) {
       $sets[] = $in[$setId];
     }

     $out = array_merge($out, call_user_func_array('array_cartesian', $sets));
   }
 }

 return $out;
}

echo "input: ".json_encode($test2);
echo "<br />output: ".json_encode(combinations($test2));

出力のサイズが非常に急速に大きくなる可能性があることは理解していますが、入力には通常、1 ~ 50 のメンバーの 1 ~ 5 セットのみを含める必要があるため、大量のセットを処理する必要はありません。

4

2 に答える 2

1

基本的に、あなたのアプローチは、入力のパワーセットを生成し、それを後処理して目的の出力に到達することでした。

直接解決しようとすることで、別の方法でアプローチすることができます。私に来た1つの解決策は次のとおりです。

入力 A = [ A 1 , ...]が与えられた場合、問題は A \ A 1について既に解かれていると仮定します。この解を S' とします。S' を A 全体の解 S に変換するにはどうすればよいでしょうか? これは本質的に、S' の 2 つのコピーを作成することによるものです。A 1の要素を最初のコピーに分配します。新しいシーケンスを S'' としましょう。したがって、A の解は単純に S'' と S' の連結になります。

アルゴリズム的に、

Input: A = [ A1, A2, ..., An]

combine(A, i, n):

  1. if n < i
  2. return []
  3. if n == i
  4. return singletons(Ai)
  5. S' = combine(A, i + 1, n)
  6. S'' = [a, S'], for each a in Ai
  7. return [S'', S']

この関数singletonsは、入力セットの 1 要素サブセットのファミリを返します。したがって、[1, 2, 3] を入力すると、[[1], [2], [3]] が返されます。

あちこちのシーケンスの連結の緩い使用法を無視すれば、アプローチは明確になるはずです...

幸運を!

于 2012-04-20T20:12:54.207 に答える
0

試す

$test = array ();
$test [0] = json_decode ( '[["A"]]', true );
$test [1] = json_decode ( '[["A"], ["B"], ["C"]]', true );
$test [2] = json_decode ( '[["A", "B"], ["C", "D", "E"], ["F"]]', true );


echo "<pre>" ;
$set = array ();
getSet ( $test, $set );
$set = array_values(array_unique($set));
$return = powerSet($set,1,3);
print_r ($return);

出力

Array
(
    [0] => Array
        (
            [0] => F
        )

    [1] => Array
        (
            [0] => E
        )

    [2] => Array
        (
            [0] => E
            [1] => F
        )

    [3] => Array
        (
            [0] => D
        )

    [4] => Array
        (
            [0] => D
            [1] => F
        )

    [5] => Array
        (
            [0] => D
            [1] => E
        )

    [6] => Array
        (
            [0] => D
            [1] => E
            [2] => F
        )

    [7] => Array
        (
            [0] => C
        )

    [8] => Array
        (
            [0] => C
            [1] => F
        )

    [9] => Array
        (
            [0] => C
            [1] => E
        )

    [10] => Array
        (
            [0] => C
            [1] => E
            [2] => F
        )

    [11] => Array
        (
            [0] => C
            [1] => D
        )

    [12] => Array
        (
            [0] => C
            [1] => D
            [2] => F
        )

    [13] => Array
        (
            [0] => C
            [1] => D
            [2] => E
        )

    [14] => Array
        (
            [0] => B
        )

    [15] => Array
        (
            [0] => B
            [1] => F
        )

    [16] => Array
        (
            [0] => B
            [1] => E
        )

    [17] => Array
        (
            [0] => B
            [1] => E
            [2] => F
        )

    [18] => Array
        (
            [0] => B
            [1] => D
        )

    [19] => Array
        (
            [0] => B
            [1] => D
            [2] => F
        )

    [20] => Array
        (
            [0] => B
            [1] => D
            [2] => E
        )

    [21] => Array
        (
            [0] => B
            [1] => C
        )

    [22] => Array
        (
            [0] => B
            [1] => C
            [2] => F
        )

    [23] => Array
        (
            [0] => B
            [1] => C
            [2] => E
        )

    [24] => Array
        (
            [0] => B
            [1] => C
            [2] => D
        )

    [25] => Array
        (
            [0] => A
        )

    [26] => Array
        (
            [0] => A
            [1] => F
        )

    [27] => Array
        (
            [0] => A
            [1] => E
        )

    [28] => Array
        (
            [0] => A
            [1] => E
            [2] => F
        )

    [29] => Array
        (
            [0] => A
            [1] => D
        )

    [30] => Array
        (
            [0] => A
            [1] => D
            [2] => F
        )

    [31] => Array
        (
            [0] => A
            [1] => D
            [2] => E
        )

    [32] => Array
        (
            [0] => A
            [1] => C
        )

    [33] => Array
        (
            [0] => A
            [1] => C
            [2] => F
        )

    [34] => Array
        (
            [0] => A
            [1] => C
            [2] => E
        )

    [35] => Array
        (
            [0] => A
            [1] => C
            [2] => D
        )

    [36] => Array
        (
            [0] => A
            [1] => B
        )

    [37] => Array
        (
            [0] => A
            [1] => B
            [2] => F
        )

    [38] => Array
        (
            [0] => A
            [1] => B
            [2] => E
        )

    [39] => Array
        (
            [0] => A
            [1] => B
            [2] => D
        )

    [40] => Array
        (
            [0] => A
            [1] => B
            [2] => C
        )

)

使用する機能

function powerSet($in, $minLength = 1, $max = 10) {
    $count = count ( $in );
    $members = pow ( 2, $count );
    $return = array ();
    for($i = 0; $i < $members; $i ++) {
        $b = sprintf ( "%0" . $count . "b", $i );
        $out = array ();
        for($j = 0; $j < $count; $j ++) {
            if ($b {$j} == '1')
                $out [] = $in [$j];
        }
        if (count ( $out ) >= $minLength && count ( $out ) <= $max) {
            $return [] = $out;
        }

    }
    return $return;
}

function getSet($array, &$vals) {
    foreach ( $array as $key => $value ) {

        if (is_array ( $value )) {

            getSet ( $value, $vals );

        } else {

            $vals [] = $value;
        }
    }

    return $vals;
}
于 2012-04-20T20:03:25.603 に答える