昨天我花了一整天时间试图解决一个问题,这个问题要求我获得第k个排列或者排除排列。 我发现最好的方法是事实数字,经过数小时的谷歌搜索和阅读数十个pdfs \ powerpoints后,我终于设法使它与铅笔,纸张和代码完美配合。
现在的问题是,当有重复的项目时。
我尝试了所有的东西,却无法按照应有的方式工作。事实上,为了排列而产生更大的排名,不能只让它“识别”非重复的排列。
有没有人知道如何使用actoradic系统来取消重复项目的排列? (例如:abaac)? 如果有人知道,那么我会喜欢一个小例子和直观的解释,这肯定会在未来有利于其他许多人。
非常感谢:)
PS:这是我尝试过的C ++代码,我写的是MYSELF。我知道它根本没有优化,只是为了告诉你到目前为止我得到了什么: 如果没有重复的项目,这段代码将正常工作,但重复项目会出错(当然,next_permutation不可用时,我想要第十亿个排列)。
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
using namespace std;
int f(int n) {
if(n<2) return 1;
return n*f(n-1);
}
int pos(string& s,char& c) {
for(int i=0;i<s.size();++i) {
if(s[i]==c) return i;
}
return -1;
}
int main() {
const char* perm = "bedac";
string original=perm;
sort(original.begin(),original.end());
string s=original;
string t=perm;
int res=0;
for(;s!=t && next_permutation(s.begin(),s.end());++res);
cout<<"real:"<<res<<endl;
s=original;
string n;
while(!s.empty()) {
int p=pos(s,t[0]);
n+=p;
t.erase(0,1);
s.erase(p,1);
}
for(res=0;!n.empty();(res+=n[0]*f(n.size()-1)),n.erase(0,1));
cout<<"factoradix:"<<res<<endl;
return 0;
}
答案 0 :(得分:2)
在所有元素都是唯一的排列中,我们可以以递归方式生成每个元素。稍微重写一下你的实现(伪代码)
def map(k,left):
ele = k/(len(left)!)
return [ele] + map( k % (len(left)!), left - left[ele])
这里我们先验地知道子集合中有多少个元素,即(k-1)!
。
在具有重复元素的排列中,剩余元素的数量为(k-1)!/((# of 1s)!(# of 2s)! ... (# of ks)!)
,并且这会根据我们在每个级别上选择的元素而更改。我们需要应用相同的想法,但是如果我们在递归的每个级别选择元素X,我们需要确定有多少子置换,而不是能够动态计算索引。我们从排列数中减去它并递归。
# group_v is the value of an element
# group_members is the number of times it is repeated
# facts_with is group_members[x] factorial
def permap(k,group_v,group_members,facts_with):
n = sum(group_members); # how many elements left
if n == 0:
return []
total = math.factorial(n-1);
total_denom = prod(facts_with);
start_range = 0; end_range = 0;
for group_i in range(len(group_v)):
if group_members[group_i] == 0:
continue
v = (group_members[group_i]*total)/(total_denom) # n-1!/((a-1)!...z!)
end_range += v
if end_range > k:
facts_with[group_i]/=group_members[group_i];
group_members[group_i]-=1;
return [group_v[group_i]] + permap(k-start_range,group_v,group_members,facts_with)
else:
start_range=end_range
raise Exception()
Python中的完整列表
#imports
import itertools;
import math;
import operator
def prod(lst):
return reduce(operator.mul,lst);
#mainfunc
def permap(k,group_v,group_members,facts_with):
n = sum(group_members);
if n == 0:
return []
total = math.factorial(n-1);
total_denom = prod(facts_with);
start_range = 0; end_range = 0;
for group_i in range(len(group_v)):
if group_members[group_i] == 0:
continue
v = (group_members[group_i]*total)/(total_denom) # n-1!/(a!...z!)
end_range += v
if end_range > k:
facts_with[group_i]/=group_members[group_i];
group_members[group_i]-=1;
return [group_v[group_i]] + permap(k-start_range,group_v,group_members,facts_with)
else:
start_range=end_range
raise Exception()
items = [1,2,2,1]
n_groups = len(list(itertools.groupby(items)))
facts_with = [0]*(n_groups)
group_v = [0]*(n_groups)
group_members = [0]*(n_groups)
group_i = 0
print [list(g) for k,g in itertools.groupby(items)];
for group in itertools.groupby(items):
group_v[group_i], group_members[group_i] = group;
group_members[group_i] = len(list(group_members[group_i]))
facts_with[group_i] = math.factorial(group_members[group_i]);
group_i+=1
for x in range(6):
print permap(x,list(group_v),list(group_members),list(facts_with));