【问题标题】:C++ All combinations of a vectorC++ 向量的所有组合
【发布时间】:2014-09-13 21:12:13
【问题描述】:

假设我们有一些来自0 to n 的数字,我们想对大小为s 的数字进行打乱,并希望查看所有可能的组合。

所以排列的数量恰好等于s! * n!/(s!*(n-s)!)

n = 3s = 3 为例:

0 1 2 | 0 1 3 | 0 2 1 | 0 2 3 | 0 3 1 | 0 3 2 | 1 0 2 | 1 0 3 | 1 3 2 
1 2 3 | 1 2 0 | 1 3 0 | 2 0 1 | 2 1 0 | 2 0 3 | 2 3 0 | 2 3 1 | 2 1 3
            3 0 1 | 3 1 0 | 3 0 2 | 3 2 0 | 3 1 2 | 3 2 1

有没有使用 boost/stl 的平滑方法来实现这一点?

【问题讨论】:

标签: c++ algorithm c++11 boost stl


【解决方案1】:

这里是使用T.C. 在 cmets (http://howardhinnant.github.io/combinations.html) 中引用的链接的代码:

#include "../combinations/combinations"
#include <iostream>
#include <vector>

int
main()
{
    std::vector<int> v{0, 1, 2, 3};
    typedef std::vector<int>::iterator Iter;
    for_each_permutation(v.begin(), v.begin()+3, v.end(),
        [](Iter f, Iter l)
        {
            for (; f != l; ++f)
                std::cout << *f << ' ';
            std::cout << "| ";
            return false;
        }
    );
    std::cout << '\n';
}

0 1 2 | 0 2 1 | 1 0 2 | 1 2 0 | 2 0 1 | 2 1 0 | 0 1 3 | 0 3 1 | 1 0 3 | 1 3 0 | 3 0 1 | 3 1 0 | 0 2 3 | 0 3 2 | 2 0 3 | 2 3 0 | 3 0 2 | 3 2 0 | 1 2 3 | 1 3 2 | 2 1 3 | 2 3 1 | 3 1 2 | 3 2 1 | 

std::next_permutation 相比,这个库的一个显着优势是被置换的元素不需要排序,甚至不需要是可比的。例如:

#include "../combinations/combinations"
#include <iostream>
#include <vector>

enum class color
{
    red,
    green,
    blue,
    cyan
};

std::ostream&
operator<< (std::ostream& os, color c)
{
    switch (c)
    {
    case color::red:
        os << "red";
        break;
    case color::green:
        os << "green";
        break;
    case color::blue:
        os << "blue";
        break;
    case color::cyan:
        os << "cyan";
        break;
    }
    return os;
}

int
main()
{
    std::vector<color> v{color::blue, color::red, color::cyan, color::green};
    typedef std::vector<color>::iterator Iter;
    for_each_permutation(v.begin(), v.begin()+3, v.end(),
        [](Iter f, Iter l)
        {
            for (; f != l; ++f)
                std::cout << *f << ' ';
            std::cout << "| ";
            return false;
        }
    );
    std::cout << '\n';
}

蓝色红色青色|蓝色青色红色|红色蓝色青色|红青蓝|青色 蓝红|青红蓝|蓝红绿|蓝绿红|红蓝 绿色 |红绿蓝|绿蓝红|绿红蓝|青色 绿色 |蓝绿青色|青蓝绿|青绿色蓝色|绿色 蓝色青色 |绿色青色蓝色|红青绿|红色绿色青色|青色 红绿|青绿色红色|绿色红色青色|青青红|

【讨论】:

    【解决方案2】:

    LIVE DEMO

    #include <algorithm>
    #include <vector>
    #include <iterator>
    #include <iostream>
    
    void dfs(int depth, int s, int i, std::vector<int>& c, const std::vector<int>& v)
    {
        if (depth == s)
        {
            do
            {
                std::copy(c.begin(), c.end(), std::ostream_iterator<int>(std::cout, " "));
                std::cout << "| ";
            }
            while (std::next_permutation(c.begin(), c.end()));
        }
        else
        {
            for (int j = i + 1; j < (int)v.size(); ++j)
            {
                c.push_back(v[j]);
                dfs(depth + 1, s, j, c, v);
                c.pop_back();
            }
        }
    }
    
    int main()
    {
        std::vector<int> v{ 0, 1, 2, 3 };
        std::sort(v.begin(), v.end());
        v.erase(std::unique(v.begin(), v.end()), v.end());    
        std::vector<int> c;
        const int length = 3;
        dfs(0, length, -1, c, v);
    }
    

    输出:

    0 1 2 | 0 2 1 | 1 0 2 | 1 2 0 | 2 0 1 | 2 1 0 | 0 1 3 | 0 3 1 | 1 0 3 |
    1 3 0 | 3 0 1 | 3 1 0 | 0 2 3 | 0 3 2 | 2 0 3 | 2 3 0 | 3 0 2 | 3 2 0 |
    1 2 3 | 1 3 2 | 2 1 3 | 2 3 1 | 3 1 2 | 3 2 1
    

    【讨论】:

    • 你的回答很优雅,能解释一下你的想法吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多