找到数组值的每个可能的排列

时间:2016-03-15 14:10:36

标签: php algorithm permutation

情况:有5个问题有多个可能的答案。其中四个问题可以有一个答案,一个问题有一个或多个答案。任何问题都没有答案。

我想弄清楚这些答案的每一种可能组合。

我认为这不是this的副本,因为它处理单个字符或数字的可能排列。

我相信这个例子会产生230,400种可能的排列

$questions = array(
    "q1" => array(
        "1a",
        "1b",
        "1c"
    ),
    "q2" => array(
        "2a",
        "2b",
        "2c",
        "2d"
    ),
    "q3" => array(
        "3a",
        "3b",
        "3c"
    ),
    "q4" => array( // this question can have any number of these answers selected, or none
        "4a",
        "4b",
        "4c",
        "4d",
        "4e",
        "4f"
    ),
    "q5" => array(
        "5a",
        "5b",
        "5c"
    )
);

1 个答案:

答案 0 :(得分:0)

我希望我的问题是对的,这个答案对你有帮助......

初始条件

除了你的例子之外,让我们介绍第二个数组,其中包含哪些问题可能有多个答案的信息:

$multi_questions = array('q4');

这将告诉我们下面描述的算法,问题4可能会选择任意数量的答案,而所有问题可能只有一个或没有答案。

答案的可能组合数

为特定问题选择的答案集独立于任何其他问题。对于总共n个可能答案和最多1个所选答案的问题,该问题的可能选择数为n+1。如果问题允许选择多个答案,则该问题可能有2^n种组合(每个答案都有两个选项:选择或未选择)。

在您的示例中,这会导致所选答案的4 * 5 * 4 * 2^6 * 4 = 20480种可能组合的总数。这个数字的计算方法如下:

$combinations = 1;
foreach ($questions as $q => $answers)
{
    if (in_array($q, $multi_questions))
        $combinations *= 1 << count($answers);
    else
        $combinations *= count($answers) + 1;
}

迭代所有可能的答案组合

如果您不仅对答案组合的数量感兴趣,而且想要全部生成它们,您可以使用如下算法。对于具有多个可能答案的问题,它将以二进制数给出的答案集编码。也就是说,数字001010代表答案集['4c','4e']

$q_keys = array_keys($questions);

// Start with no answer selected for any question
$answer_set = array();
$q_max = array();
for ($i = 0; $i < count($q_keys); $i++)
{
    $answer_set[$i] = 0;
    $q_max[$i] = (in_array($q_keys[$i], $multi_questions))
                 ? (1 << count($questions[$q_keys[$i]])) - 1
                 : count($questions[$q_keys[$i]]);
}

// Iterate over all combinations of answers
while ($answer_set[0] <= $q_max[0])
{

    // Decode answer set to array of selected answers for each question
    $answers = array();
    for ($i = 0; $i < count($q_keys); $i++)
    {
        if (in_array($q_keys[$i], $multi_questions))
        {
            $answers[$q_keys[$i]] = array();
            for ($a = 0; $a < count($questions[$q_keys[$i]]); $a++)
                if (($answer_set[$i] & (1 << $a)) != 0) // Is the bit corresponding to answer no. $a set?
                    $answers[$q_keys[$i]][] = $questions[$q_keys[$i]][$a];
        }
        else
            $answers[$q_keys[$i]] = ($answer_set[$i] > 0)
                                    ? array($questions[$q_keys[$i]][$answer_set[$i] - 1])
                                    : array(); // Encode no answer as empty array
    }

    // Do something with the array of answers for each question ($answers)
    // ...

    // Forward the answer set
    for ($i = count($q_keys) - 1; $i >= 0; $i--)
    {
        if (++$answer_set[$i] > $q_max[$i] && $i > 0)
            $answer_set[$i] = 0;
        else
            break;
    }

}