假设我有一个排序数组 N ,由 n 元素组成。现在,给定 k ,我需要一种高效的方法来生成k组合,这种组合将是中间组合(如果所有 k - 组合都按字典顺序排序)。< / p>
示例:
N = {a,b,c,d,e} , k = 3
1:a,b,c
2:a,b,d
3:a,b,e
4:a,c,d
5:a,c,e
6:a,d,e
7:b,c,d
8:b,c,e
9:b,d,e
10:c,d,e
我需要算法来生成组合编号5.
组合数字系统上的维基百科页面解释了如何获得(以贪婪的方式)。但是,由于 n 非常大,我需要找到所有 k 小于 n 的中间组合,我还需要更多东西比那更有效率。
我希望由于感兴趣的组合始终位于中间,因此有一种直接的方法可以找到它。例如,上面列表中的第一个k组合总是由 N 中的第一个 k 元素给出,类似地,最后一个组合总是由最后一个 k 元素。有没有这种方法可以找到中间组合?
答案 0 :(得分:0)
如果您正在寻找从词典索引或独特组合的等级中获取K指数的方法,那么您的问题属于二项式系数。二项式系数处理在K组中选择唯一组合以及总共N个项目的问题。
我在C#中编写了一个类来处理使用二项式系数的常用函数。它执行以下任务:
以任意N选择K到文件的格式输出所有K索引。 K-index可以用更具描述性的字符串或字母代替。
将K索引转换为正确的词典索引或排序二项式系数表中条目的等级。这种技术比依赖迭代的旧发布技术快得多。它通过使用Pascal三角形中固有的数学属性来实现这一点,并且与迭代集合相比非常有效。
将已排序的二项系数表中的索引转换为相应的K索引。使用的技术也比旧的迭代解决方案快得多。
使用Mark Dominus方法计算二项式系数,这样就不太可能溢出并使用更大的数字。
该类是用.NET C#编写的,它提供了一种通过使用通用列表来管理与问题相关的对象(如果有)的方法。此类的构造函数采用名为InitTable的bool值,当为true时,将创建一个通用列表来保存要管理的对象。如果此值为false,则不会创建表。为了使用上述4种方法,不需要创建该表。提供访问者方法来访问该表。
有一个关联的测试类,它显示了如何使用该类及其方法。它已经在几个案例中进行了广泛的测试,并且没有已知的错误。
要阅读此课程并下载代码,请参阅Tablizing The Binomial Coeffieicent。
以下测试代码将计算任何N选择K组合的中位词典元素:
void TestMedianMethod()
{
// This test driver tests out the GetMedianNChooseK method.
GetMedianNChooseK(5, 3); // 5 choose 3 case.
GetMedianNChooseK(10, 3); // 10 choose 3 case.
GetMedianNChooseK(10, 5); // 10 choose 5 case.
}
private void GetMedianNChooseK(int N, int K)
{
// This method calculates the median lexicographic index and the k-indexes for that index.
String S;
// 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);
// Calculate the median value, which in this case is the number of combos for this N
// choose K case divided by 2.
int MedianValue = NumCombos / 2;
// The Kindexes array holds the indexes for the specified lexicographic element.
int[] KIndexes = new int[K];
// Get the k-indexes for this combination.
BC.GetKIndexes(MedianValue, KIndexes);
StringBuilder SB = new StringBuilder();
for (int Loop = 0; Loop < K; Loop++)
{
SB.Append(KIndexes[Loop].ToString());
if (Loop < K - 1)
SB.Append(" ");
}
// Print out the information.
S = N.ToString() + " choose " + K.ToString() + " case:\n";
S += " Number of combos = " + NumCombos.ToString() + "\n";
S += " Median Value = " + MedianValue.ToString() + "\n";
S += " KIndexes = " + SB.ToString() + "\n\n";
Console.WriteLine(S);
}
<强>输出:强>
5 choose 3 case:
Number of combos = 10
Median Value = 5
KIndexes = 4 2 0
10 choose 3 case:
Number of combos = 120
Median Value = 60
KIndexes = 8 3 1
10 choose 5 case:
Number of combos = 252
Median Value = 126
KIndexes = 9 3 2 1 0
您应该能够轻松地将此课程移植到您选择的语言上。您可能不必移植类的通用部分来实现您的目标。根据您使用的组合数量,您可能需要使用大于4字节整数的字大小。