在C ++中生成N选择K排列 [英] Generating N choose K Permutations in C++

查看:113
本文介绍了在C ++中生成N选择K排列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个函数,它接收n和k来创建n选择k的所有可能排列,虽然它适用于5选择3或3选择2等大多数组合,但不适用于4选择2的其他组合我需要一些帮助来查找和理解该错误。感谢您的光临。

I have a function that receives n and k to create all the possible permutations of n choose k, and while it works for most combinations like 5 choose 3 or 3 choose 2, it doesn't for for others like 4 choose 2. I need some help finding and understanding the bug. Thanks for looking.

函数:

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

I'm using the next_permutation function. cplusplus

当我尝试4选择2,我应该得到12个排列,而不是我得到这个:

When I try 4 choose 2, I should be getting 12 permutations, instead I get this:

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种可能的排列:

Whereas, 3 choose 2 works perfectly with 6 possible permutations:

1 2 
1 3   
2 1   
2 3   
3 1   
3 2             


推荐答案

前k个值重复nk个阶乘。这是避免重复的一种简单但有效的方法:

The first k values are repeated n-k factorial times. Here is an easy, although inefficient, way to avoid the repetition:

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的方法更简单,更有效::反向(来自 https://stackoverflow.com/a/2616837/951890

However, there is an even easier and more efficient way to do it using std::reverse (from https://stackoverflow.com/a/2616837/951890)

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()));
}

这里的诀窍是要意识到最后的排列只是第一个排列,因此通过反转最后nk个元素,您会自动跳到这些元素的最后一个排列。

The trick here is to realize that the last permutation is just the reverse of the first permutation, so by reversing the last n-k elements, you automatically skip to the last permutation of those elements.

这篇关于在C ++中生成N选择K排列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆