如何使用 Factoradic 系统获取或取消具有重复项的 K 排列
昨天我花了一整天的时间试图解决一个问题,该问题需要我得到第 k 个排列或取消排列的排名。 我发现最好的方法是因子数,经过几个小时的谷歌搜索和阅读数十个 pdf\powerpoints,我终于成功地用铅笔和纸以及代码完美地工作了。
现在的问题是,当有重复的项目时。
我尝试了一切,但无法让事情按照应有的方式工作。因子总是为排列生成更大的排名,不能只是让它“识别”非重复的排列。
有谁知道如何使用行动系统对重复项目的排列进行取消排名? (例如:abaac)? 如果有人知道,请我喜欢一个小例子和直观的解释,这肯定会让将来的许多其他人受益。
非常感谢:)
PS:这是我自己编写的尝试的 C++ 代码。我知道它根本没有优化,但只是为了向您展示到目前为止我得到的结果: 如果没有重复的项目,此代码将正确工作,但如果重复的项目,则会出现错误(当然,当我想要第 10 亿个排列时,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;
}
Yesterday I spent the entire day trying to solve a problem that wants me to get the k-th permutation or unrank a permutation.
I found the best way was factoradic numbers, after hours of Googling and reading dozens of pdfs\powerpoints I finally managed to make it work perfectly both with pencil and paper and by code.
Problem now is, when there are repeated items.
I tried everything, but couldn't get the thing to work the way it should.The factoradic always generates much bigger rank for a permutation, can't just let it "recognize" only non-repeated permutations.
Does anyone know a way to use the actoradic system to unrank a permutation with repeated items ? (eg: abaac) ?
If anyone knows, please I would love a small example and intuitive explanation, that sure will benifit many others in the future.
Thanks a lot :)
PS: Here is my attempted C++ code that I wrote MYSELF.I know its not optmized at all, but just to show you what I got so far:
This code will work correct if no repeated items, but will be wrong with repeated items (next_permutation is not usable of course when say, I want the 1 billionth 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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在所有元素都是唯一的排列中,我们可以以递归方式生成每个元素。稍微重写一下你的实现(用伪代码)
这里我们先验地知道子集合中有多少个元素,即
(k-1)!
。在具有重复元素的排列中,剩余元素的数量为
(k-1)!/((# of 1s)!(# of 2s)! ... (# of ks)!)
这会根据我们在每个级别选择的元素而变化。我们需要应用相同的想法,但是我们需要确定如果我们在递归的每个级别选择元素 X,则有多少个子排列,而不是能够即时计算索引。我们从排列数中减去它并递归。Python 中的完整列表
In a permutation where all elements are unique, we can generate each element, in a recursive fashion. To rewrite your implementation a bit (in pseudo-code)
Here we know a priori how many elements are in the subcollection, namely
(k-1)!
.In a permutation with repeated elements, the number of remaining elements is
(k-1)!/((# of 1s)!(# of 2s)! ... (# of ks)!)
and this changes based on what element we choose on each level. We need to apply the same idea, but instead of being able to calculate the index on the fly, we need to determine how many sub-permutations there are if we choose element X at each level of the recursion. We subtract that from the permutation number and recurse.The full listing in Python