找到满足给定条件的排列

时间:2017-02-17 13:45:24

标签: c++ algorithm count permutation

我想找出n数字的所有排列的数量。数字将从1n。给定的条件是每个ith位置都可以号码最多为Si,其中每个号码位置都会Si

1<=n<=10^6
1<=si<=n

例如:

n=5

然后它的所有五个元素将是

1,2,3,4,5

并给出每个位置的Si为:

2,3,4,5,5

它显示在: 1st位置可以1 to 2 1,2,但不能在3 to 5中编号。 同样的,  在2nd位置只能有1 to 3个号码。  在3rd位置只能有1 to 4个号码。  在4th位置只能有1 to 5个号码。  在5th位置只能有1 to 5个号码。 它的一些排列是:

1,2,3,4,5
2,3,1,4,5
2,3,4,1,5 etc.

但这些不可能是:

3,1,4,2,5  As 3 is present at 1st position.
1,2,5,3,4  As 5 is present at 3rd position.

我不知道在给定条件下计算所有可能的排列数。

4 个答案:

答案 0 :(得分:2)

好的,如果我们保证在而不是降序顺序中给出数字si,那么看起来可以计算O(n)中的排列数。 / p>

直接算法的想法如下:

  1. 在步骤i将结果乘以si[i]当前值;
  2. 我们为位置i选择了一些号码。只要我们需要排列,这个数字就不能重复,所以其余si[k]ki+1到结尾(例如n)减少1; < / LI>
  3. i增加1,返回(1)。
  4. 举例说明si: 2 3 3 4

    1. result = 1;
    2. 当前si是“2 3 3 4”,result *= si[0](= 1 * 2 == 2),减少3,3和4乘以1;
    3. 当前si为“.2 2 3”,result *= si[1](= 2 * 2 == 4),最后2和3减1;
    4. 当前si是“.... 1 2”,result *= si[2](= 4 * 1 == 4),将最后一个数字减少1;
    5. 当前si是“..... 1”,result *= si[3](= 4 * 1 == 4),已完成。
    6. 由于步骤减少,这种直截了当的方法需要O(n^2)。为了优化它,我们可以很容易地观察到result *= si[i]时刻我们的si [i]已经精确地减少i次(假设我们从0开始)。

      因此O(n)方式:

      unsigned int result = 1;
      for (unsigned int i = 0; i < n; ++i)
      {
          result *= (si[i] - i);
      }
      

答案 1 :(得分:0)

对于每个si计数数组中元素的数量,使得a [i]&lt; = si使用二进制搜索,并将值存储到数组count [i],现在答案是所有计数的乘积[ i],但是我们减少了答案中的冗余数量(因为相同的数字可以计数两次),因为你可以对si进行排序并检查多少个数字是&lt; = s [i],然后减少每个数字算,复杂度是O(nlog(n)),希望至少我给你一个想法。

答案 2 :(得分:0)

要完成Yuriy Ivaskevych的回答,如果您不知道sis是否按顺序增加,您可以对sis进行排序,它也可以。 如果排列是不可能的,结果将为空或否定(例如:1 1 1 1 1)

答案 3 :(得分:-1)

你可以尝试回溯,这是一个小硬核方法,但会起作用。 尝试: http://www.thegeekstuff.com/2014/12/backtracking-example/ 或google回溯教程C ++