【发布时间】:2021-03-08 23:23:31
【问题描述】:
给定一组 8 个连续数字{0..7} 分成 4 组大小为 2,每组中的数字按升序排列,如何为该集合生成排名?排名应按字典顺序排列,算法的复杂度最好是线性的。
分区示例:
{{0 1} {2 3} {4 5} {6 7}} // Rank 0
...
{{6 7} {4 5} {2 3} {0 1}} // Rank 2519
因为每个组中的数字是按升序排列的,所以这些组被有效地视为组合,而不是排列,所以一个组包含例如{5 4} 永远不会发生。
这组数字如何在[0, 2520) (8C2 * 6C2 * 4C2) 范围内按顺序排列?
目前我将每个组的排名计算为 8C2 组合,然后将每个排名组合在一起,将其视为 base-28 数字。这显然会在排名中留下差距,这在我的情况下是不可取的。但是,就其价值而言,这是我目前的排名。
#include <array>
using std::array;
#include <cstdint>
#include <cstddef>
#include <iostream>
using std::cout;
using std::endl;
// Calculates n!.
uint32_t factorial(uint32_t n)
{
return n <= 1 ? 1 : n * factorial(n - 1);
}
// Calculate nCk: n!/((n-k)!*k!).
uint32_t choose(uint32_t n, uint32_t k)
{
return (n < k)
? 0
: factorial(n) / (factorial(n - k) * factorial(k));
}
template<size_t N, size_t K>
class CombinationRanker
{
array<array<uint32_t, K+1>, N+1> choices;
public:
/**
* Initialize a precomputed array of nCk (N and K inclusive).
*/
CombinationRanker()
{
for (unsigned n = 0; n <= N; ++n)
for (unsigned k = 0; k <= K; ++k)
this->choices[n][k] = choose(n, k);
}
/**
* Get the rank of a combination.
* @param comb A combination array of size K in ascending order.
*/
uint32_t rank(const array<uint8_t, K> comb) const
{
// Formula: (nCk) - ((n-c_1)Ck) - ((n-c_2)C(k-1)) - ... - ((n-c_k)C1)
// That assumes 1-based combinations with ranks starting at 1, so each
// element in the combination has 1 added to it, and the end result has 1
// subtracted from it to make the rank 0-based.
uint32_t rank = this->choices[N][K];
for (unsigned i = 0; i < K; ++i)
rank -= this->choices[N - (comb[i] + 1)][K - i];
return rank - 1;
}
};
int main(int argc, char* argv[])
{
CombinationRanker<8, 2> ranker;
array<array<uint8_t, 2>, 4> nums =
{{
{0, 1}, {2, 3}, {4, 5}, {6, 7}
}};
// Horribly sparse rank.
unsigned rank =
ranker.rank(nums[0]) * 28 * 28 * 28 +
ranker.rank(nums[1]) * 28 * 28 +
ranker.rank(nums[2]) * 28 +
ranker.rank(nums[3]);
cout << rank << endl; // 10835, but I want 0.
return 0;
}
我已将帖子标记为 C++,因为这是我正在使用的语言;但是,另一种语言的答案很好。这更像是一个数学问题,但我正在寻找一个我作为程序员而不是数学家可以理解的答案,并且代码 sn-p 在这方面会有所帮助。
【问题讨论】:
标签: c++ combinatorics