【问题标题】:Conditional Lexicographical Permutations条件词典排列
【发布时间】:2013-04-12 21:51:15
【问题描述】:

所以我已经阅读了可以生成字典排列的算法。 如:1-2-3-4-5->1-2-3-5-4->1-2-4-3-5->...->5-4-3-2-1

但是我想强加一些布尔条件,我跳过一些排列。

假设我有: 1-2-3-4-5 1-2-3-5-4 . . . 我想跳过所有其他 1-2-X-X-X 然后转到 1-3-2-4-5

交换 2 和 3 并对剩余的三个数字进行排序是最好的方法吗? 还是有其他更快的方法?

【问题讨论】:

  • 你想使用什么类型的布尔条件?您提出的建议如下所示:如果已经生成 (1,2,3,4,5) 和 (1,2,3,5,4),那么如果当前生成的排列的开头是 (1,2),则跳过。描述您要使用的布尔条件。
  • 所以对于数字 1,2,3,4,5 我有 5 个!排列。对于前面有 1-2 的排列,我有 3 个!该类型的排列。我想施加一个布尔条件,这样当前两个数字加起来为 3 时,我会跳过 1-2-X-X-X 类型的所有其他排列并转到 1-3-2-4-5。

标签: c++ algorithm permutation


【解决方案1】:

我仍然不太明白你的问题,但从我看到的你可以基于这段代码:

vector<int> permutation;
for (int i = 1; i < N; ++i)
   permutation.push_back(i);
void gen_perm(int level, vector<int>& per){
  if (level < N-1);
    for (int i = level; i < N; ++i) {
        swap(per[level], per[i]);
        gen_perm(level + 1, per);
        swap(per[level], per[i]);
    }
  else
    print(per) or return per or whatever you want to do with perms.
}

现在,条件呢?您可以将它们传递给 gen_perm 函数,例如指向返回 bool 并采用级别和排列(引用)的函数的指针向量,如果条件在给定级别失败,则不做任何事情返回,所以假设您可以创建这样的乐趣:

bool check_3(int level, vector<int>& perm) {
   if (level == 2)
      if (perm[0] + perm[1] == 3) return false;
   return true;
}

我建议你先:

typedef bool (*cond_fun)(int, vector<int>&);

例如在 gen_loop 中使用它们:

void gen_perm(int level, vector<int>& per, vector<cond_fun>& conds){
  if (level < N-1);
    for (int i = 0; i < conds.size(); ++i) {
       if (!(*conds[i])(level, per)) return;
    }
    for (int i = level; i < N; ++i) {
        swap(per[level], per[i]);
        gen_perm(level + 1, per, conds);
        swap(per[level], per[i]);
    }
  else
    print(per) or return per or whatever you want to do with perms.
}

当然,如果你有额外的知识,你可以改进它:每个条件最多可以失败一次,所以如果它们返回 false,你可以从向量中删除它们。

【讨论】:

  • 好吧,我正在尝试使用应用于分支和绑定上下文的排列。因此,对于每个数字:1、2、3,......我将有一个相应的“成本”,如果部分排列的累积“成本”超过我的限制,我想提前修剪一个。一旦部分排列超过我的限制,我不想计算该形式的其他排列。我想跳到下一个部分排列。
  • 所以在我所说的例子中,如果数字 1-2 的累积成本已经超过我的限制,我只想生成 1-3 的排列,因为我不想浪费时间计算 1-2-3-4-5、1-2-3-5-4 等
  • 感谢您的贡献,但对我来说,他的问题是如何制定一个允许从部分排列快速转换到下一个顺序的例程,例如从 1-2-X-X-X 到 1-3-2- 4-5 或 1-2-4-3-5 到 1-2-5-3-4。
  • @XYZ 这就是我的代码所做的......这个成本如何与排列中的位置相关联?
  • 您的代码没有显示如何跳过一些排列,例如 1-2-4-3-5 -> 1-3-2-4-5。
【解决方案2】:

您所询问的内容称为阶乘基数,您可以在需要时以正确的数量推进计数器。你可以在这里阅读更多相关信息:http://efesx.com/2009/11/14/enumerating-permutations/(以及http://marknelson.us/2002/03/01/next-permutation/

【讨论】:

    猜你喜欢
    • 2019-10-24
    • 2013-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多