排列组合 C++实现

本文介绍了两种计算排列组合的方法。第一种是基于分治思想的递归实现,通过排列组合公式Cij来计算;第二种是利用二进制位移操作,通过将所有元素设置标志位并进行位操作来生成所有可能的组合。这两种方法分别适用于不同的场景,并提供了C++代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考文章:
1.https://blog.youkuaiyun.com/deepmindman/article/details/52264007
2.https://liam.page/2016/01/31/binomial-in-cpp/

排列

从n个数中,有顺序地选择m个。A(n,m)
例如,A(3,2)=6. 所有的组合分别是{1,2},{1,3},{2,3},{2,1},{3,1},{3,2}
A(n,m)=n!/[m!]

组合

从n个数中,无顺序地选择m个。C(n,m)
例如,C(3,2)=3. 所有的组合分别是{1,2},{1,3},{2,3}.
C(n,m)=n!/[m!*(n-m!)]
思路1:分治思想,递归实现。

/*****************************************************************************************************************************
        时间复杂度:
        空间复杂度:
        功能:求排列组合Cij
        输入参数:
                int i                :        总数
                int j                :          组合数
                vector<int>r:        用于存储临时结果的向量,大小必须等于num 
                int num                :        组合数
                vector<vector<int> > & result        :        用于存储最终所有结果的二维向量 
        返回参数:
                void
        注意: 
                首先建立两个向量作为函数的输入参数                
                vector<int> r(num);                                //num为组合数 
                vector<vector<int> > result;        //存储最终结果 
        使用样例:
                vector<int> resulttemp(3);
                vector<vector<int> > result;
                Cij(6,3,resulttemp,3,result); 
*****************************************************************************************************************************/
 
 
void Cij(int i, int j,vector<int> &r,int num,vector<vector<int> > & result)
{
        //排列组合公式Cij
        //cout << n << ' ' << i << ' ' << j << endl;
        if (j == 1)
        {
                for (int k = 0; k < i; k++)
                {
                        vector<int> temp(num);
                        r[num - 1] = k;
                        for (int i = 0; i < num;i++)
                        {
                                temp[i]=r[i];
                                //cout << r[i] << ' ';
                        }
                        result.push_back(temp);
                        //cout << endl;
                }
        }
        else if (j == 0)
        {
                //do nothing!
        }
        else
        {
                for (int k = i; k >= j; k--)
                {
                        r[j-2] = k-1;
                        Cij(k - 1, j - 1,r,num,result);
                }
        }
}

思路2:将所有元素设置标志位,被选的元素标为1,没被选的标为0。
选择过程:C(n,k)。k个1的二进制位不断向后移动。

binomial.cc





using namespace std;
vector<string>& combination
  (vector<string>& res, const size_t& choose, const size_t& from);
bool compare (const char& lhs, const char& rhs);
int main () {
  vector<string> res;
  const size_t choose = 3, from = 5;
  combination (res, choose, from);
  for (size_t i = 0; i != res.size(); ++i) {
    cout << res[i] << '\t';
    for (size_t j = 0; j != from; ++j) {
      if (res[i][j] == '1') {
        cout << j + 1 << ' ';
      }
    }
    cout << endl;
  }
  return 0;
}
vector<string>& combination
  (vector<string>& res, const size_t& choose, const size_t& from) {
  string wk = string (choose, '1') + string (from - choose, '0');
  res.push_back (wk);
  size_t found = string::npos;
  while ((found = wk.find("10")) != string::npos) {
    // 1. swap found
    wk[found] ^= wk[found + 1];
    wk[found + 1] ^= wk[found];
    wk[found] ^= wk[found + 1];
    // 2. sort before
    sort (wk.begin(), wk.begin() + found, compare);
    res.push_back (wk);
  }
  return res;
}
bool compare (const char& lhs, const char& rhs) {
  return lhs > rhs;
}

参考文章:
作者: Liam Huang
原文链接: https://liam.page/2014/09/28/review-of-the-continent/
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
感谢

### C++ 实现排列组合算法 #### 排列算法实现 C++标准库提供了`<algorithm>`头文件中的两个函数用于处理排列:`next_permutation()` 和 `prev_permutation()`。这些函数可以用来生成给定序列的所有可能排列。 对于一个包含重复元素的数组,这两个函数会按照字典序依次返回下一个或上一个排列。当所有排列都已遍历完毕,则返回`false`[^4]。 ```cpp #include <iostream> #include <vector> #include <algorithm> int main() { std::vector<int> nums = {1, 2, 3}; do { for (auto num : nums) { std::cout << num << " "; } std::cout << "\n"; } while (std::next_permutation(nums.begin(), nums.end())); return 0; } ``` 这段代码展示了如何利用`do...while`循环配合`next_permutation()`来打印出所有的排列情况。 #### 组合算法实现 要计算组合数并枚举具体的组合项,可以通过递归来完成。下面是一个简单的例子,它实现了从集合中选取指定数量元素的功能: ```cpp void combine(std::vector<int>& data, int start, int k, std::vector<std::vector<int>>& result, std::vector<int>& current) { if (k == 0) { result.push_back(current); return; } for (size_t i = start; i != data.size(); ++i) { current.push_back(data[i]); combine(data, i + 1, k - 1, result, current); current.pop_back(); } } // 使用示例 int main() { std::vector<int> set = {1, 2, 3, 4, 5}; // 原始数据集 size_t subsetSize = 3; // 要选出的数量 std::vector<std::vector<int>> combinations; std::vector<int> temp; combine(set, 0, subsetSize, combinations, temp); // 打印结果 for (const auto& comb : combinations) { for (int elem : comb) { std::cout << elem << ' '; } std::cout << '\n'; } return 0; } ``` 此程序定义了一个名为`combine`的辅助函数来进行实际的选择操作,并通过调用该函数获取到所有满足条件的不同子集。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值