在C++中生成N个选K个排列

6
我是一名能够翻译文本的助手。
我有一个函数,它接收n和k来创建所有可能的n选k排列,虽然它适用于大多数组合,比如5选3或3选2,但对于其他一些组合,比如4选2,它就不起作用了。我需要帮助找到并理解这个问题。谢谢你的关注。
函数如下:
void PermGenerator(int n, int k)    
{    
    int d[] = {1,2,3,4,5,6,7,8,9};  
    sort (d, d+n);  
    cout << "These are the Possible Permutations: " << endl;  
    do  
    {  
        for (int i = 0; i < k; i++)  
        {  
            cout << d[i] << " ";  
            if (i == k-1) cout << endl;  
        }  
    } while (next_permutation(d, d+n));  
}  

我正在使用next_permutation函数。cplusplus 当我尝试4选2时,我应该得到12个排列,但实际上我得到的是:
1 2    
1 2   
1 3   
1 3   
1 4   
1 4   
2 1   
2 1     
2 3   
2 3   
2 4   
2 4   
3 1   
3 1   
3 2   
3 2   
3 4   
3 4   
4 1   
4 1   
4 2   
4 2   
4 3   
4 3         

然而,3选2在6种可能的排列中完美运作:

1 2 
1 3   
2 1   
2 3   
3 1   
3 2             
3个回答

9

前k个值重复n-k次阶乘。这里有一种简单但效率低下的方法可以避免重复:

int Factorial(int n)
{
  int result = 1;
  while (n>1) {
    result *= n--;
  }
  return result;
}

void PermGenerator(int n, int k)
{
    std::vector<int> d(n);
    std::iota(d.begin(),d.end(),1);
    cout << "These are the Possible Permutations: " << endl;
    int repeat = Factorial(n-k);
    do
    {
        for (int i = 0; i < k; i++)
        {
            cout << d[i] << " ";
        }
        cout << endl;
        for (int i=1; i!=repeat; ++i)
        {
            next_permutation(d.begin(),d.end());
        }
    } while (next_permutation(d.begin(),d.end()));
}

然而,使用std::reverse(来自https://dev59.com/MnE95IYBdhLWcg3wp_yn#2616837)有一种更简单、更有效的方法。

void PermGenerator(int n, int k)
{
    std::vector<int> d(n);
    std::iota(d.begin(),d.end(),1);
    cout << "These are the Possible Permutations: " << endl;
    do
    {
        for (int i = 0; i < k; i++)
        {
            cout << d[i] << " ";
        }
        cout << endl;
        std::reverse(d.begin()+k,d.end());
    } while (next_permutation(d.begin(),d.end()));
}

这里的技巧在于意识到最后一种排列只是第一种排列的倒序,因此通过反转最后的n-k个元素,您就自动跳到了这些元素的最后一种排列。

谢谢!这个方法很管用。正如MBo在上面所说,我输出了数组的前k个元素,但我没有看到。 - Corghee
1
@Corghee:请注意,使用std::reverse可以更轻松、高效地完成此操作。请参见https://dev59.com/MnE95IYBdhLWcg3wp_yn#2616837。 - Vaughn Cato

3
您可以使用以下内容:
template <typename T>
void Combination(const std::vector<T>& v, std::size_t count)
{
    assert(count <= v.size());
    std::vector<bool> bitset(v.size() - count, 0);
    bitset.resize(v.size(), 1);

    do {
        for (std::size_t i = 0; i != v.size(); ++i) {
            if (bitset[i]) {
                std::cout << v[i] << " ";
            }
        }
        std::cout << std::endl;
    } while (std::next_permutation(bitset.begin(), bitset.end()));
}

实时示例

(该链接为实时演示)

1
你需要输出每n!个排列中的前k个成员。 4! = 24种排列方式,前两种排列为:
1,2,3,4
1,2,4,3

你有1、2和1、2。

要获取组合(4,2),你可以使用向量,例如:

 {0,0,1,1}

对其进行排列组合,并输出1的索引。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接