【问题标题】:Elegant Way To Generate Composite Permutations in C++在 C++ 中生成复合排列的优雅方法
【发布时间】:2018-10-21 21:03:48
【问题描述】:

我有一个 Test 类,它包含一个 Letter 类的两个向量,这是一个用户定义的类型,已为其实现了小于运算符 (

class Test
{
  vector<Letter> letter_box_a;
  vector<Letter> letter_box_b;
}

因此,如果 letter_box_a 包含字母 A 和 B,并且 letter_box_b 包含 C 和 D,则 Test 的有效排列将是 (AB)(CD)、(BA)(CD)、(AB)(DC) 和 (BA)(直流)。

虽然我可以暴力破解它,但我试图编写一个更好(更优雅/高效)的函数,该函数将在底层容器上内部调用 std::next_permutation 允许我这样做

Test test;
while (test.set_next_permutation())
{
    // Do the stuff
}

但这似乎比我最初预期的要复杂一些。我不一定需要 STL 解决方案,但想要一个优雅的解决方案。

【问题讨论】:

    标签: c++ stl permutation


    【解决方案1】:

    我认为你可以做类似的事情

    bool Test::set_next_permutation() {
        auto &a = letter_box_a, &b = letter_box_b;  // entirely to shorten the next line
        return std::next_permutation(a.start(), a.end()) || std::next_permutation(b.start(), b.end());
    }
    

    (当然,while 循环在任何情况下都会跳过初始排列。您需要一个 do...while 循环。)

    【讨论】:

    • 感谢您的回答,我将对其进行测试。我考虑了这条路线,但我认为它会首先给出 letter_box_a 的所有排列,只有 letter_box_b 的初始排列,然后是 letter_box_b 的所有排列,只有 letter_box_a 的最终排列。我弄错了吗?
    • 是的。 next_permutation 不记得你从哪里开始,因此不知道何时停止;它依赖于排列中元素的顺序。您可以一遍又一遍地置换同一个组,并且它只会在每次返回到“第一个”时返回 false。所以发生的情况是第一组被一遍又一遍地排列,每次它环绕时,第二组也被排列。只有当两个排列都回绕时,函数才会返回 false。
    【解决方案2】:

    如果您想使用std::next_permutation,您需要为每个要置换的向量使用一个嵌套循环:

    std::string s0 = "ab";
    std::string s1 = "cd";
    
    do
    {
        do
        {
            cout << s0 << "" << s1 << endl;
        } while (std::next_permutation(s0.begin(), s0.end()));
    } while (std::next_permutation(s1.begin(), s1.end()));
    

    输出:

    abcd
    bacd
    abdc
    badc
    

    而且,在课堂上:

    class Foo
    {
    public:
        Foo(std::string_view arg_a, std::string_view arg_b)
            : a(arg_a)
            , b(arg_b)
            , last(false)
        { }
    
        void reset_permutations()
        {
            last = false;
        }
    
        bool next_permutation(std::string& r)
        {
            if (last)
                return false;
    
            if (not std::next_permutation(a.begin(), a.end()))
                if (not std::next_permutation(b.begin(), b.end()))
                    last = true;
    
            r = a + b;
            return true;
        }
    
    private:
        std::string a, b;
        bool last;
    };
    
    int main(int argc, const char *argv[])
    {
        Foo foo("ab", "cd");
        string s;
        while (foo.next_permutation(s))
            cout << s << endl;
        return 0;
    }
    

    【讨论】:

    • 感谢您的回答,这也是我第一次接触它的方式,也许我只是累了,但似乎有一个问题是班级的外部用户如何在没有的情况下对每个排列做一些事情访问内部?
    • 由于我们不能像 Python 中那样依赖 yield,我们必须保留一小块内部状态来返回所有排列(事件第一个)。
    猜你喜欢
    • 2011-04-06
    • 2015-03-22
    • 1970-01-01
    • 2010-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-24
    • 2023-03-15
    相关资源
    最近更新 更多