C++ 生成不包括循环旋转的所有置换
因此,我需要一个算法来生成不包括循环旋转的数字列表的所有置换(例如,[1,2,3]=[2,3,1]=[3,1,2]) 当序列中至少有一个唯一的数字时,它是相当直接的,取出该唯一的数字,生成剩余数字的所有排列(但对“标准”排列算法进行一点修改),并将唯一的数字添加到前面 为了生成置换,我发现有必要将置换代码更改为:C++ 生成不包括循环旋转的所有置换,c++,algorithm,rotation,permutation,C++,Algorithm,Rotation,Permutation,因此,我需要一个算法来生成不包括循环旋转的数字列表的所有置换(例如,[1,2,3]=[2,3,1]=[3,1,2]) 当序列中至少有一个唯一的数字时,它是相当直接的,取出该唯一的数字,生成剩余数字的所有排列(但对“标准”排列算法进行一点修改),并将唯一的数字添加到前面 为了生成置换,我发现有必要将置换代码更改为: def permutations(done, options) permuts = [] seen = [] for each o in options
def permutations(done, options)
permuts = []
seen = []
for each o in options
if o not in seen
seen.add(o)
permuts += permutations(done+o, options.remove(o))
return permuts
仅使用选项中的每个唯一数字一次意味着您不会获得322次
该算法在没有唯一元素时仍然输出旋转,例如对于[1,1,2,2],它将输出[1,1,2,2]、[1,2,2,1]和[1,2,1,2],前两个是循环旋转
那么,有没有一种有效的算法可以让我生成所有的排列,而不必在之后通过移除循环旋转
如果没有,什么是消除循环旋转的最有效方法
<强>注:这不是使用Python,而是C++(
< P>)。这个解决方案将涉及到一点使用,以及一些好的OLL模式集差异。请记住,查找置换的运行时仍然是O(n!)。我的解决方案也不会在线进行,但可能有一个更优雅的解决方案允许您这样做(并且不涉及itertools.permutations
)。为此,这是完成任务的简单方法
步骤1:使用给定的第一个元素生成循环的算法。对于列表[1,1,2,2]
,这将为我们提供[1,1,2,2],[1,2,2,1],[2,1,1,2],[2,2,1,1]
def rotations(li):
count = 0
while count < len(li):
yield tuple(li)
li = li[1:] + [li[0]]
count += 1
第三步:使用生成器为我们提供自己的集合,以及循环(我们想要摆脱的东西)
步骤4:对每个应用设置差异,然后删除循环
perm = perm.difference(cycles)
希望这能帮到你。我愿意接受建议和/或更正。考虑测试您输出的每个排列,寻找比您得到的排列“词汇上”更早的循环旋转。如果有,不要返回它-它将在其他地方被枚举 选择“唯一”的第一个元素(如果存在)有助于优化。你知道如果你修复了第一个元素,并且它是唯一的,那么你就不可能通过旋转来复制它。另一方面,如果没有这样独特的元素,只需选择出现最少的元素。这样,您只需要检查具有第一个元素的循环旋转。(例如,当您生成[1,2,2,1]时,您只需要检查[1,1,2,2],而不是[2,2,1,1]或[2,1,1,2])
好的,伪代码。。。显然是O(n!),我确信没有比这更聪明的方法了,因为“所有符号都不同”的情况显然必须返回(n-1)!元素
// generate all permutations with count[0] 0's, count[1] 1's...
def permutations(count[])
if(count[] all zero)
return just the empty permutation;
else
perms = [];
for all i with count[i] not zero
r = permutations(copy of count[] with element i decreased);
perms += i prefixed on every element of r
return perms;
// generate all noncyclic permutations with count[0] 0's, count[1] 1's...
def noncyclic(count[])
choose f to be the index with smallest count[f];
perms = permutations(copy of count[] with element f decreased);
if (count[f] is 1)
return perms;
else
noncyclic = [];
for each perm in perms
val = perm as a value in base(count.length);
for each occurence of f in perm
test = perm rotated so that f is first
tval = test as a value in base(count.length);
if (tval < val) continue to next perm;
if not skipped add perm to noncyclic;
return noncyclic;
// return all noncyclic perms of the given symbols
def main(symbols[])
dictionary = array of all distinct items in symbols;
count = array of counts, count[i] = count of dictionary[i] in symbols
nc = noncyclic(count);
return (elements of nc translated back to symbols with the dictionary)
//生成计数为[0]0、计数为[1]1的所有置换。。。
def置换(计数[])
如果(计数[]全部为零)
只返回空排列;
其他的
perms=[];
尽管我的计数不是零
r=排列(元素i减少时计数[]的副本);
perms+=i,在r的每个元素上加前缀
回烫;
//生成计数为[0]0,计数为[1]1的所有非循环置换。。。
def非循环(计数[])
选择f作为计数最小的索引[f];
排列=排列(元素f减少时计数[]的副本);
如果(计数[f]为1)
回烫;
其他的
非循环=[];
烫发中的每一次烫发
val=作为基数(count.length)值的perm;
在perm中每次出现f
测试=旋转perm,使f位于第一位
tval=测试作为基准值(计数长度);
如果(tval
对于所有数字都不同的排列,这很简单。假设数字是1,2,…,n
,然后生成1,2,…,n-1的所有排列,并将n
粘贴在前面。这给出了全集模循环旋转的所有置换。例如,使用n=4
,您可以
4 1 2 3
4 1 3 2
4 2 1 3
4 2 3 1
4 3 1 2
4 3 2 1
这确保1,2,3,4
的每个排列的某些循环旋转在列表中正好出现一次
对于一般情况,您需要多集的置换(允许重复条目),您可以使用类似的技巧。删除最大字母n
的所有实例(类似于在上例中忽略4
),并生成剩余多集的所有排列。下一步是以规范的方式将n
s放回排列中(类似于上例中将4
放在开头)
这实际上只是一个查找所有要生成的实例。首先,我将展示我们将使用的容器和算法
#include <vector>
#include <set>
#include <algorithm>
#include <iostream>
#include <iterator>
using std::vector;
using std::set;
using std::sort;
using std::next_permutation;
using std::copy;
using std::ostream_iterator;
using std::cout;
我们需要一个比较对象来检查排列是否为旋转:
struct CompareCyclicPermutationsEqual
{
bool operator()(const Permutation& lhs, const Permutation& rhs);
};
以及使用循环比较对象的typedef
aset
:
typedef set<Permutation, CompareCyclicPermutationsEqual> Permutations;
我还没有实现compareCyclePermutationSequal
。另外,当我运行代码时,您需要实现ostream&operatorHmm,似乎返回set([(1,2,1,2),(2,1,2,1)]
,而不是(1,1,2,2)和(1,2,1,2)。此外,我更喜欢与python无关的东西,因为我实际上是在C++中编写这篇文章的,不知道为什么会包含python标记。对我来说,这有点误导
typedef vector<unsigned int> Permutation;
struct CompareCyclicPermutationsEqual
{
bool operator()(const Permutation& lhs, const Permutation& rhs);
};
typedef set<Permutation, CompareCyclicPermutationsEqual> Permutations;
int main()
{
Permutation permutation = {1, 2, 1, 2};
sort(permutation.begin(). permutation.end());
Permutations permutations;
do {
permutations.insert(permutation);
} while(next_permutation(numbers.begin(), numbers.end()))
copy(permutations.begin(), permutations.end(),
ostream_iterator<Permutation>(cout, "\n");
return 0;
}
1, 1, 2, 2,
1, 2, 1, 2,