找到满足给定条件的排列

Posted

技术标签:

【中文标题】找到满足给定条件的排列【英文标题】:Finding the permutation that satisfy given condition 【发布时间】:2017-02-17 13:45:24 【问题描述】:

我想找出nnumber 的所有排列的个数。编号将从1n。给定条件是每个ithposition 最多可以有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 21,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.

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

【问题讨论】:

这是一些编程比赛吗?还是裁判问题? 它不属于任何正在运行的编码竞赛。但它需要我的编码实现。 @coderredoc 已经提到了 n 和 Si 的给定限制。 您需要只需要排列的数量 还是排列本身?对于您的示例,究竟有多少排列是可能的? @Yuriy 只有排列的次数。 【参考方案1】:

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

直截了当的算法思路如下:

    在步骤i 将结果乘以si[i]当前值; 我们为位置i 选择了一些数字。只要我们需要排列,这个数字就不能重复,所以将所有其余的si[k] 其中ki+1 到末尾(例如n)减1; 将i 增加 1,返回 (1)。

si: 2 3 3 4 为例说明:

    result = 1; 当前si 为“2 3 3 4”,result *= si[0] (= 1*2 == 2),将 3、3 和 4 减 1; 当前si 为“..2 2 3”,result *= si[1] (= 2*2 == 4),最后 2 和 3 减 1; 当前si 为“....1 2”,result *= si[2] (= 4*1 == 4),将最后一个数字减1; 当前si 是“..... 1”,result *= si[3] (= 4*1 == 4),完成。

但是,由于步数减少,这种简单的方法需要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);

【讨论】:

【参考方案2】:

对于每个 si 计算数组中元素的数量,使得 a[i]

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:

您可以尝试回溯,这是一种有点硬核的方法,但会奏效。 尝试: http://www.thegeekstuff.com/2014/12/backtracking-example/ 或者google回溯教程C++

【讨论】:

n 最大为 1e6,这会得到 TLE,即使 O(n^2) 也会得到 TLE。 @Alex Banu,我对回溯知之甚少,请解释如何针对这个问题实施回溯。

以上是关于找到满足给定条件的排列的主要内容,如果未能解决你的问题,请参考以下文章

如何更有效地从n组中找到满足给定条件的最小组合?

编程之美之高速寻找多个数满足给定条件

c语言 查找并输出满足给定条件的一组整数

全排列 II(力扣第47题)

R语言-查找满足条件的数并获取索引

七.Excel统计函数