32卡组的特定排列(C中)

32卡组的特定排列(C中),c,algorithm,permutation,playing-cards,C,Algorithm,Permutation,Playing Cards,我想生成32个卡片组的所有排列,我将卡片表示为数字0-7,所以我不关心卡片的颜色。游戏很简单,把牌分成两张格罗布牌,比较两张牌,把两张牌加到一组较大的牌上。我已经为游戏的这一部分编写了代码,但现在甲板是随机生成的,我想看看所有可能的牌,并做一些统计。我如何给这张卡片编码?我完全不知道如何编码。因为我刚刚研究了Aaron Williams 2009年通过前缀移位实现的多集置换的无循环生成,我将提供他的算法版本,它精确地解决了这个问题。我相信它比标准的C++ NExtx排列更快,因为这个问题不依赖于

我想生成32个卡片组的所有排列,我将卡片表示为数字0-7,所以我不关心卡片的颜色。游戏很简单,把牌分成两张格罗布牌,比较两张牌,把两张牌加到一组较大的牌上。我已经为游戏的这一部分编写了代码,但现在甲板是随机生成的,我想看看所有可能的牌,并做一些统计。我如何给这张卡片编码?我完全不知道如何编码。

因为我刚刚研究了Aaron Williams 2009年通过前缀移位实现的多集置换的无循环生成,我将提供他的算法版本,它精确地解决了这个问题。我相信它比标准的C++ NExtx排列更快,因为这个问题不依赖于搜索输入向量的枢轴点。但需要更广泛的基准测试才能得出明确的答案;很可能它最终会移动更多的数据

Williams的算法实现通过将排列存储在一个链表中避免了数据移动,这允许前缀移位将向量的前缀旋转一个位置,只需修改下两个指针即可实现。这使得算法没有循环

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

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

第二,它使用后缀移位而不是前缀移位;实际上,与Williams的实现相比,它产生了每个置换的相反结果。我这样做是因为它简化了对启动条件的描述

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

代码如下:

/* 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;
}
如果评论不清楚,您可以使用以下命令来生成一副4*k牌的所有洗牌,而不考虑花色:

unsigned n = 4 * k;
int v[n];
for (unsigned i = 0; i < k; ++i)
  for (unsigned j = 0; j < 4; ++j)
    v[4 * i + j] = i;

unsigned state = 1;
do {
  /* process the permutation */ 
} while ((state = multipermute_step(v, n, state);

实际上,尝试为k==8这样做需要一段时间,因为有32个/4.8种可能的洗牌。大约是2.39*1024。但我确实在0.3秒内完成了16张牌的所有洗牌,我估计我可以在半小时内完成20张牌。

请明确和具体地回答你的问题。也试着把你用它试过的东西贴出来,要求更清晰。不要指望别人会为你做充分的尝试!我想生成32张牌组的所有排列。你的目标可能实现吗?请记住,与地球上的原子相比,有规则的牌组有更多的方法来排列一副牌。看一看可能会给你一些提示。是的,没错:好吧,我必须通过一些数学理论来减少这种可能性。。。。为了好玩,编写这个问题的最佳选项是什么?排列有时数组对不同的牌有影响,有时没有?统计数据必须从概率理论推导出来,而不是通过生成所有牌的排列。如果你使用一个小得多的牌组是可能的,这将允许你通过经验测试理论是否正确,如果是,将理论扩展到32张牌组。生成32张牌的所有排列将至少需要7500万年,即使你只关心数字。即使这是可能的,你的问题仍然会过于宽泛,因为你要求的是一个完整的教程,这对于一篇SO文章来说太长了。从研究如何生成置换开始,并尝试自己实现它。如果您在执行时遇到一些困难,我们将很乐意提供帮助。32张牌和4套西装的排列数量不是32吗/4!^8.有4个!4张相同号码的牌的排列,共有8组。@fei:是的,你说得对。我会把找的钱还给你。我用一个糟糕的基准测试愚弄了自己。现在,我更彻底地进行了基准测试,它并没有比std::next_迭代提供明显的加速。