C++ 排列中的交换数
是否有一种有效的算法(在大O表示法方面是有效的)来找到交换数,从而将置换p转换为恒等置换I?互换不需要在相邻的元素上,而是在任何元素上 例如:C++ 排列中的交换数,c++,algorithm,permutation,C++,Algorithm,Permutation,是否有一种有效的算法(在大O表示法方面是有效的)来找到交换数,从而将置换p转换为恒等置换I?互换不需要在相邻的元素上,而是在任何元素上 例如: I = {0, 1, 2, 3, 4, 5}, number of swaps is 0 P = {0, 1, 5, 3, 4, 2}, number of swaps is 1 (2 and 5) P = {4, 1, 3, 5, 0, 2}, number of swaps is 3 (2 with 5, 3 with 5, 4 with 0) 一
I = {0, 1, 2, 3, 4, 5}, number of swaps is 0
P = {0, 1, 5, 3, 4, 2}, number of swaps is 1 (2 and 5)
P = {4, 1, 3, 5, 0, 2}, number of swaps is 3 (2 with 5, 3 with 5, 4 with 0)
一个想法是编写如下算法:
int count = 0;
for(int i = 0; i < n; ++ i) {
for(; P[i] != i; ++ count) { // could be permuted multiple times
std::swap(P[P[i]], P[i]);
// look where the number at hand should be
}
}
int count=0;
对于(int i=0;i
但我不太清楚这是否真的保证终止,或者它是否找到了正确的互换数量。它适用于上述示例。我尝试在5和12个数字上生成所有排列,它总是在这些数字上终止
这个问题出现在数值线性代数中。一些矩阵分解使用旋转,它有效地将具有最大值的行交换给下一个要操作的行,以避免被小数字除法并提高数值稳定性。某些分解,如LU分解,可在以后用于计算矩阵行列式,但如果排列数为奇数,则分解行列式的符号与原始矩阵的符号相反
编辑:我同意这个问题类似于。但我认为这个问题更为根本。将一个置换转换为另一个置换可以转化为这个问题,方法是将O(n)中的目标置换反转,在O(n)中组合置换,然后找到从那里到标识的交换数。通过将身份显式表示为另一个置换来解决这个问题似乎是次优的。另外,直到昨天,另一个问题有四个答案,其中只有一个(由| \/| ad)看起来有用,但对方法的描述似乎含糊不清。现在,用户lizusek在这里回答了我的问题。我不同意以重复的方式结束这个问题
EDIT2:正如用户rcgldr在评论中指出的,建议的算法实际上似乎是相当优化的,请参见我对的回答。我认为关键是要根据 这表示任何置换都是不相交循环的产物 关键事实是:
S(x[0],…,x[n-1])
是将x
转换为{0,1,…,n-1}
所需的最小掉期数量,则:
x[n-1]==n-1
,则S(x)==S(x[0],…,x[n-2])
(即,切断最后一个元素)x[-1]!=n-1
,然后S(x)==S(x[0],…,x[n-1],…,x[i],…x[n-2])+1
,其中x[i]==n-1
S({})=0
S(x)
的简单算法,该算法在O(n)
时间内运行:
int num_swaps(int[] x, int n) {
if (n == 0) {
return 0;
} else if (x[n - 1] == n - 1) {
return num_swaps(x, n - 1);
} else {
int* i = std::find(x, x + n, n - 1);
std::swap(*i, x[n - 1])
return num_swaps(x, n - 1) + 1;
}
}
@我没有这方面的书。它几乎没有什么关系,因为分解可以简单地返回它所做的排列数量,而不需要计算。我从理论的角度对这种算法感兴趣。如果您对学习数值方法感兴趣,我建议您购买最新版的数值公式()。您可以计算乘法因子的循环长度,这将告诉您需要多少次交换才能将其转换为标识。请注意,每次交换都会在其适当位置放置至少一个元素,所以对于n个数,效率是O(n)。我不知道如何才能获得更高的效率。可能重复的,我们可以重新打开这个,这样我可以粘贴一个完整的C++实现,在我被迫提出的那一刻?第一篇文章中的示例代码将比这个递归方法快,尽管两者都是O(n)。这是O(n)还是更像O(n log n)和最坏情况O(n^2/2),因为
std::find()
?可能复杂性取决于交换的数量和交换的方式。@如果你是对的,这种方法可能是O(n^2)。使用哈希映射作为查找的反向索引而不是std::find
可能会得到O(n)。