32个卡片组的特定排列(以C表示)

时间:2018-07-21 16:43:00

标签: c algorithm permutation playing-cards

我想生成32张卡片组的所有排列,我将卡片表示为数字0-7,所以我不在乎卡片的颜色。游戏非常简单(将套牌分成两个大块,比较两张卡,将两张卡添加到较大卡组中)。我已经编写了游戏的这一部分,但是卡组现在是随机生成的,并且我想查看纸牌的所有可能性,并对其进行一些统计。我该如何编码生成的卡?我完全不知道如何编码。

1 个答案:

答案 0 :(得分:1)

因为我只是在研究Aaron Williams 2009年的论文“通过前缀移位无循环生成多集置换”,所以我将贡献他的算法的一个版本,该算法正是解决了这个问题。我认为它比通常为此问题引用的标准C ++ next_permutation更快,因为它不依赖于在输入向量中搜索枢轴点。但是,需要更广泛的基准测试才能得出确定的答案。很有可能最终会移动更多数据。

威廉姆斯算法的实现通过将置换存储在链接列表中来避免数据移动,这允许仅修改两个{{1}就可以实现“前缀移位”(将向量的前缀旋转一个位置) }指针。这使算法无环。

我的版本在几个方面有所不同。

  • 首先,它使用普通数组存储值,这意味着移位确实需要循环。另一方面,它避免了必须实现链接列表数据类型,并且对数组的许多操作都更快。

  • 第二,它使用后缀移位而不是前缀移位;实际上,它产生每个排列的相反结果(与Williams的实现相比)。我这样做是因为它简化了开始条件的描述。

  • 最后,它只执行一个排列步骤。 Williams算法的一大优点是置换序列的状态可以封装在单个索引值中(当然也可以封装置换本身)。此实现返回要提供给下一个调用的状态。 (由于状态变量最后将为0,因此返回值将作为终止指示符加倍。)

代码如下:

next

万一评论不清楚,您可以使用以下代码来制作4 * k张卡片的所有混洗,而无需考虑西装的问题:

/* Do a single permutation of v in reverse coolex order, using
 * a modification of Aaron Williams' loopless shift prefix algorithm.
 * v must have length n. It may have repeated elements; the permutations
 * generated will be unique.
 * For the first call, v must be sorted into non-descending order and the
 * third parameter must be 1. For subsequent calls, the third parameter must
 * be the return value of the previous call. When the return value is 0,
 * all permutations have been generated.
 */
unsigned multipermute_step(int* v, unsigned n, unsigned state) {
  int old_end = v[n - 1];
  unsigned pivot = state < 2 || v[state - 2] > v[state] ? state - 1 : state - 2;
  int new_end = v[pivot];
  for (; pivot < n - 1; ++pivot) v[pivot] = v[pivot + 1];
  v[pivot] = new_end;
  return new_end < old_end ? n - 1 : state - 1;
}

实际上尝试对k == 8进行此操作需要一段时间,因为存在32!/(4!) 8 可能的随机播放。大约是2.39 * 10 24 。但是我确实在0.3秒内完成了16张牌的全部洗牌,而且我估计半小时内可以完成20张牌。