计算所有n个大小的排列而不重复且没有“经典”排序

时间:2011-11-11 11:25:37

标签: php algorithm unique permutation

好的,我需要为照片竞赛实现这个...我有一组主要的N张照片,我需要生成那些照片的第2张的排列,而不需要重复,例如:

foo.png VS bar.png

等于

bar.png VS foo.png

另一件事,我不能每次都预先生成排列,所以我需要一个函数,给定前一个排列,将返回下一个(如果可能的唯一排列结束,则返回NULL)。

我使用以下PHP函数解决了这个问题:

function getNextPermutation( $aPermutableItems, $iPermutationSize, $aPreviousPermutation = NULL )
{
  $aNextPermutation = $aPreviousPermutation;
  $iLastIndex       = $iPermutationSize - 1;
  $iPermutableItems = count($aPermutableItems);

  // Any previous permutation ?
  if( $aPreviousPermutation )
  {
    // Loop the elements backwards
    for( $i = $iLastIndex; $i >= 0; $i-- )
    {
      // Can the current element be incremented without reaching the limit ?
      if( ++$aNextPermutation[ $i ] >= $iPermutableItems )
      {
        // Increment the previous element
        $iPrevValue = ++$aNextPermutation[ $i - 1 ];
        // Reset the current element with the value of the previous plus one
        $iNextValue = $aNextPermutation[ $i ] = $iPrevValue + 1;
        // Skip the previous element because it was just incremented
        $i--;
        // If one of the two elements reached the limit, we are in the exit condition
        if( $iPrevValue >= $iPermutableItems || $iNextValue >= $iPermutableItems )
          return FALSE;
      }
      // Limit still to be reached for the i-th element, skip previous ones
      else
        break;
    }
  }
  // Am i able to generate the first permutation ?
  else if( $iPermutationSize <= $iPermutableItems )
    $aNextPermutation = range( 0, $iLastIndex );
  // Permutation impossible to generate because we don't have enough elements in the main set
  else
    $aNextPermutation = FALSE;

  return $aNextPermutation;
}

那样:

$iPerm  = 0;
$aPrev  = NULL;
$aItems = array( 0, 1, 2, 3, 4 );

while( ($aPrev = getNextPermutation( $aItems, 2, $aPrev )) != FALSE )
{
  echo sprintf( "%2d : %s\n", $iPerm++, implode( ', ',  $aPrev ) ); 
}

将输出:

0 : 0, 1
1 : 0, 2
2 : 0, 3
3 : 0, 4
4 : 1, 2
5 : 1, 3
6 : 1, 4
7 : 2, 3
8 : 2, 4
9 : 3, 4

现在,我真的想为它添加一些熵...我的意思是,正如你所看到的,组合中的第一项经常重复(0,1 0,2 0,3),并且在我的情况下这不好,因为我会看到4个连续排列的相同图片。

有没有办法修改(或重新实现)我的算法以获得类似(例如)的内容:

0 : 0, 1
1 : 1, 2
2 : 0, 3
3 : 3, 4
4 : 0, 2
5 : 1, 3
6 : 0, 4
7 : 2, 3
8 : 2, 4
9 : 1, 4

显然我不能随意改变排列数组,因为正如我所写,我没有整个排列数组,只有先前的排列将在我的算法应用后给出下一个排列。

PS:每次挑战我都有大约500张照片,因此存储位掩码或类似的东西是不可接受的。

感谢。

2 个答案:

答案 0 :(得分:1)

如果您希望以未排序的方式对大小k进行一些排列,则可以在基数2中使用n位的计数器,并打印下一个值(具有k 1)每次,例如大小为3(和k = 2)的计数器:

000
001
010
011
100
101
110

所以,你的输出将是011,101和110(实际上将转换为(1,2),(3,1),(3,2))它不是你想要的但是当计数器大小时增长,它会更明智,但使用这样的计数器是耗时的,但如果你的图片大小小于20它足够快(因为2 ^ 20 = 100万不大)。同样通过获得100这样的数字,您只需启动计数器并获得下一个值即可。此外,这只是可扩展的,以生成大小为k的排列。

答案 1 :(得分:1)

创建一个包含k个和N-k个零的数组。 然后使用C ++ std :: next_permutation算法,其工作原理如下:

  1. 从左边开始,找到最右边的一个,然后是零。
  2. 将一个替换为零并对数组的其余部分进行排序。
  3. 例如, 从0 0 0 0 1 1 1

    开始

    找到最右边的一个5,将其移动到位置4: 0 0 0 1 0 1 1

    对其余部分进行排序: 0 0 0 1 0 1 1

    找到最合适的位置6,将其移动到位置5: 0 0 0 1 1 0 1

    对其余部分进行排序: 0 0 0 1 1 0 1

    找到最右边的一个7,将其移动到位置6: 0 0 0 1 1 1 0

    对其余部分进行排序: 0 0 0 1 1 1 0

    找到最右边的一个4,将其移动到位置3: 0 0 1 0 1 1 0

    对其余部分进行排序: 0 0 1 0 0 1 1

    等等......

相关问题