下一个词汇“置换”算法

时间:2016-11-11 19:45:49

标签: c++ algorithm permutation

我编写了一个程序,解决了24(link的广义版本。也就是说,给定一组n个数字,是否有办法对它们执行二进制运算,以便它们计算到目标数。

为此,我将可能的表达式视为由'v''o'组成的字符数组,其中'v'是值的占位符,'o'是占位符的操作。请注意,如果有n个值,则必须进行n-1次操作。

程序当前的工作原理是它按字典顺序检查{'o','o',...,'v',v'...}的每个排列,并查看前缀表达式是否有效。例如,n = 4时,以下表达式被视为有效:

{‘o’,’o’,’o’,’v’,’v’,’v’,’v’}
{‘o’, ‘v’, ‘o’, ‘v’, ‘o’, ‘v’, ‘v’}

以下表达式无效:

{‘v’,’o’,’v’,’o’,’o’,’v’,’v’}

{‘o’,’o’,’v’,’v’,’v’,’o’,’v’}

我的问题是,是否存在一种有效的算法来获得在某种排序中有效的下一个排列?目标是消除必须检查表达式是否对每个排列都有效。

此外,如果存在这样的算法,是否存在O(1)时间来计算k有效排列?

到目前为止我有什么

我假设长度A的前缀表达式2n-1被认为是有效的,当且仅当

每个number of operations < number of values

A[i:2n-1)

其中0<=i<2n-1(从i开始到2n-1结束(不包括)的子阵列

此外,这意味着在(1/n)C(2n-2,n-1)C(n,k)的情况下,确实存在n choose k个有效排列。

1 个答案:

答案 0 :(得分:2)

以下是如何生成ov - 模式。下面代码背后的细节是在Knuth Volume 4A中(或至少提到过;我可能已经完成了其中一个练习)。在更改模式之前,您可以使用现有的置换机制来对每个方向的值进行置换。

代码

#include <cstdio>

namespace {
void FirstTree(int f[], int n) {
  for (int i = n; i >= 0; i--) f[i] = 2 * i + 1;
}

bool NextTree(int f[], int n) {
  int i = 0;
  while (f[i] + 1 == f[i + 1]) i++;
  f[i]++;
  FirstTree(f, i - 1);
  return i + 1 < n;
}

void PrintTree(int f[], int n) {
  int i = 0;
  for (int j = 0; j < 2 * n; j++) {
    if (j == f[i]) {
      std::putchar('v');
      i++;
    } else {
      std::putchar('o');
    }
  }
  std::putchar('v');
  std::putchar('\n');
}
}

int main() {
  constexpr int kN = 4;
  int f[1 + kN];
  FirstTree(f, kN);
  do {
    PrintTree(f, kN);
  } while (NextTree(f, kN));
}

生成输出

ovovovovv
oovvovovv
ovoovvovv
oovovvovv
ooovvvovv
ovovoovvv
oovvoovvv
ovoovovvv
oovovovvv
ooovvovvv
ovooovvvv
oovoovvvv
ooovovvvv
oooovvvvv

有一种方法可以获得第k个树,但是在时间O(n)而不是O(1)。神奇的单词是unranking binary trees