C++ 大集合的第n个或任意组合
假设我有一组来自C++ 大集合的第n个或任意组合,c++,algorithm,permutation,combinations,C++,Algorithm,Permutation,Combinations,假设我有一组来自[0,…,499]的数字。当前使用C++代码> STD::NExtx置换< /COD>顺序生成组合。作为参考,我提取的每个元组的大小是3,因此我返回顺序结果,如[0,1,2],[0,1,3],[0,1,4]。。。[497498499] 现在,我想对代码进行并行化,这样连续生成这些组合就不再有效了。是否有任何现有算法可用于计算500个数字中3的第i个组合 我想确保每个线程,不管它得到的循环的迭代次数如何,都可以基于它正在迭代的I计算一个独立的组合。因此,如果我想要线程1中I=38的
[0,…,499]
的数字。当前使用C++代码> STD::NExtx置换< /COD>顺序生成组合。作为参考,我提取的每个元组的大小是3,因此我返回顺序结果,如[0,1,2],[0,1,3],[0,1,4]。。。[497498499]
现在,我想对代码进行并行化,这样连续生成这些组合就不再有效了。是否有任何现有算法可用于计算500个数字中3的第i个组合
我想确保每个线程,不管它得到的循环的迭代次数如何,都可以基于它正在迭代的I
计算一个独立的组合。因此,如果我想要线程1中I=38
的组合,我可以计算[1,2,5]
,同时将线程2中的I=0
计算为[0,1,2]
编辑下面的陈述无关紧要,我把自己搞糊涂了
我看过一些算法,它们利用阶乘从左到右缩小每个元素的范围,但我不能把它们当作500!当然不适合记忆。有什么建议吗?您可以将500个对象中的3个对象描述为三个
(i,j,k)
,其中i
是从0到499的数字(第一个数字的索引),j
范围从0到498(第二个的索引,跳过第一个数字),而k
范围从0到497(最后一个的索引,跳过之前选择的两个数字)。因此,枚举所有可能的选择实际上非常容易:从(0,0,0)开始
,递增k
直到达到其最大值,然后递增j
并将k
重置为0,依此类推,直到j
达到其最大值,依此类推,直到j
达到其自身的最大值;然后递增i
并将j
和k
重置并继续
如果这个描述听起来很熟悉,那是因为它的工作原理与增加一个以10为基数的数字的工作原理完全相同,只是基数要有趣得多,而且实际上基数在数字之间是不同的。你可以利用这一观点来实现这个想法的一个非常简洁的版本:对于从0到500*499*498的任何整数n
,你可以得到:
struct {
int i, j, k;
} triple;
triple AsTriple(int n) {
triple result;
result.k = n % 498;
n = n / 498;
result.j = n % 499;
n = n / 499;
result.i = n % 500; // unnecessary, any legal n will already be between 0 and 499
return result;
}
void PrintSelections(triple t) {
int i, j, k;
i = t.i;
j = t.j + (i <= j ? 1 : 0);
k = t.k + (i <= k ? 1 : 0) + (j <= k ? 1 : 0);
std::cout << "[" << i << "," << j << "," << k << "]" << std::endl;
}
void PrintRange(int start, int end) {
for (int i = start; i < end; ++i) {
PrintSelections(AsTriple(i));
}
}
struct{
int i,j,k;
}三重;
三重阿斯特里普(int n){
三重结果;
结果:k=n%498;
n=n/498;
结果:j=n%499;
n=n/499;
result.i=n%500;//不需要,任何合法的n都将在0和499之间
返回结果;
}
无效打印选择(三重t){
int i,j,k;
i=t.i;
j=t.j+(i如果您正在寻找一种方法来获得唯一组合的字典索引或秩,而不是排列,那么您的问题属于二项式系数。二项式系数处理的问题是,在总共N个项目的K组中选择唯一组合
我用C#编写了一个类来处理处理处理二项式系数的常用函数。它执行以下任务:
将任意N选择K的所有K索引以良好的格式输出到文件中。K索引可以替换为更多描述性字符串或字母
将K-索引转换为已排序的二项式系数表中条目的适当词典索引或秩。此技术比依赖迭代的较旧已发布技术快得多。它通过使用Pascal三角形固有的数学特性来实现这一点,与在集合上迭代相比非常有效
将排序后的二项式系数表中的索引转换为相应的K索引。我相信它也比旧的迭代解决方案快
使用此方法计算二项式系数,它不太可能溢出,并且适用于较大的数字
该类是用.NET C#编写的,提供了一种管理与问题相关的对象(如果有)的方法通过使用泛型列表。该类的构造函数接受一个名为InitTable的bool值,如果为true,将创建一个泛型列表来保存要管理的对象。如果该值为false,则它将不会创建该表。使用上述4种方法不需要创建该表。提供了访问器方法来访问e桌
有一个相关的测试类,它展示了如何使用这个类及其方法。它已经用2个案例进行了广泛的测试,并且没有已知的bug
要阅读有关此类的信息并下载代码,请参阅
以下测试代码将遍历每个唯一的组合:
public void Test10Choose5()
{
String S;
int Loop;
int N = 500; // Total number of elements in the set.
int K = 3; // Total number of elements in each group.
// Create the bin coeff object required to get all
// the combos for this N choose K combination.
BinCoeff<int> BC = new BinCoeff<int>(N, K, false);
int NumCombos = BinCoeff<int>.GetBinCoeff(N, K);
// The Kindexes array specifies the indexes for a lexigraphic element.
int[] KIndexes = new int[K];
StringBuilder SB = new StringBuilder();
// Loop thru all the combinations for this N choose K case.
for (int Combo = 0; Combo < NumCombos; Combo++)
{
// Get the k-indexes for this combination.
BC.GetKIndexes(Combo, KIndexes);
// Verify that the Kindexes returned can be used to retrive the
// rank or lexigraphic order of the KIndexes in the table.
int Val = BC.GetIndex(true, KIndexes);
if (Val != Combo)
{
S = "Val of " + Val.ToString() + " != Combo Value of " + Combo.ToString();
Console.WriteLine(S);
}
SB.Remove(0, SB.Length);
for (Loop = 0; Loop < K; Loop++)
{
SB.Append(KIndexes[Loop].ToString());
if (Loop < K - 1)
SB.Append(" ");
}
S = "KIndexes = " + SB.ToString();
Console.WriteLine(S);
}
}
public void Test10Choose5()
{
字符串S;
内环;
int N=500;//集合中的元素总数。
int K=3;//每组中的元素总数。
//创建获取所有数据所需的bin coeff对象
//此N选择K组合的组合。
BinCoeff BC=新的BinCoeff(N,K,false);
int NumCombos=BinCoeff.GetBinCoeff(N,K);
//Kindexes数组指定lexigraphic元素的索引。
int[]KIndexes=新的int[K];
StringBuilder SB=新的StringBuilder();
//循环通过此N选择K案例的所有组合。
for(int-Combo=0;Comboint k = 527; //The kth combination is calculated
int N=500; //Number of Elements you have
int a=0,b=1,c=2; //a,b,c are the numbers you get out
while(k >= (N-a-1)*(N-a-2)/2){
k -= (N-a-1)*(N-a-2)/2;
a++;
}
b= a+1;
while(k >= N-1-b){
k -= N-1-b;
b++;
}
c = b+1+k;
cout << "["<<a<<","<<b<<","<<c<<"]"<<endl; //The result