关于题目
题目描述:取n个数组成为数组,从其中取m个数字组成一个组合,共有多少个这样的组合,并把具体的组合列举出来。
- 看完题目很多人开始从公式着手得出组合数即
C n m C_{n}^{m} Cnm得出结果,或者用 C n m = C n − 1 m + C n − 1 m − 1 C_{n}^{m}=C_{n-1}^{m}+C_{n-1}^{m-1} Cnm=Cn−1m+Cn−1m−1采用递归方法得出组合数。
可是有没有想过要是这样那如何得出组合的具体数据呢?
关于解题
所以我跳开了公式,采取最简单粗暴的方法来递归。
我以{1,2,3}
C
3
2
C_{3}^{2}
C32来举例:
那么以这个为思想我们可以写出暴力递归的基本框架了:
/*参数:需要组合的数组s,
临时存放排列数组的temp,
排列数需要满足的长度k,
以及用以控制每次递归循环的开始处x,
用于存放答案的二维数组res
*/
void dfs()
{
//递归触底的条件
if(temp的长度等于k){
将temp序列放入res中;
return;
}
for(int i=x;i<s数组的元素个数;i++){
将s[i]存入数组temp中;
dfs(temp,s,k,i+1);
当dfs触底后将数组temp的最后一个元素弹出;
}
}
我这样写也是为了让没有C++基础的同学看懂。。
下面我将介绍详细代码
关于代码
/*
s一维数组用于存储需要排列的数字。
res二维数组用于存储每次具体的排列。
temp一维数组用于存储每个排列数的数字。
*/
#include<bits/stdc++.h>
using namespace std;
vector<vector<int>>res;
vector<int>temp;
vector<int>s;
//dfs函数用于遍历s中的数字,然后创建对应的答案填入res中。
/*
参数k表示每个排列需要多少个数字,即从n个数字中取m个数字组成排列中的m
参数x用于让子问题不重复,即1,2,3取两个数,我们先从1开始然后得出1,2和1,3而不会有1,1
同理从2开始也只会有2,3,这就是每次递归时参数x取i+1的缘由
既然是递归解决,兄弟们还是老老实实把递归树先画出来吧。。。
*/
void dfs(vector<int>&temp,vector<int>&s,int k,int x){
if(temp.size()+s.size()-x<k)return;
//判断子情况是否能满足k个元素
if(temp.size()==k){
res.push_back(temp);
return;
}
for(int i=x;i<s.size();i++){
temp.push_back(s[i]);
dfs(temp,s,k,i+1);
temp.pop_back();
}
}
int main(){
//输入n个数字,并从n个数字中取m个数字组成排列
int n;
int m;
int h;
cin >> n>>m;
for(int i=0;i<n;i++){
cin >>h;
s.push_back(h);
}
dfs(temp,s,m,0);//递归建立res数组得出答案
printf("There are %d groups of permutations.\n",res.size());//输出得出多少个排列数
cout << "The specific number of permutations is:"<<endl;//输出具体的排列数字
for(int j=0;j<res.size();j++){
for(int q:res[j])
{cout<<q<<',';}
cout<<'\n';
}
}