口袋取球
在一个口袋里有x种不同编号的小球(编号从1开始到x),现允许取y次,问取次的结果有哪些可能的情况,为方便区分,要求对取出的小球按编号从大到小进行排序。
输入格式:
在一行中输入两个整数,以空格隔开,分别代表x, 和y。
输出格式:
对每一组可能,在一行中输出这组对应的小球的编号,编号之间以空格分隔,每一行必须以一个回车结束。
输入样例:
在这里给出一组输入。例如:
3 2
输出样例:
在这里给出相应的输出。例如:
3 2 3 1 2 1
这个问题可以使用全排列的类似做法,只是仔细读题会发现,2和1相当于1和2,所以只能取1个就可以了,不用回退到所有 前面已经选择的数。
第一种解法:
组合数,位置标记法
#include<iostream>
using namespace std;
int n,m;//n为有多少个小球,m是取多少次
int res[10000];
void dfs(int x,int n){
if(x == m+1){
for(int i = 1;i <= m;i++){
cout<<res[i]<<" ";
}
cout<<endl;
return;
}
for(int i = n;i>=1;i--){
res[x] = i;
dfs(x+1,n-1);
}
}
int main(){
cin>>n>>m;
dfs(1,n);//位置,取得次数
return 0;
}
注意:dfs(x+1,i-1)为dfs( 位置,数字)//这个数字是减少的,不会再从头开始选择
第二种解法:
子集树,参考01背包问题选择与不选择的判断
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
int n,m;//小球编号 和 取球次数
vector<int> p;//存放临时解
void dfs(int x,int count){
if(count == n){
if(p.size() ==2){
for(int i = 0 ; i < 2;i++)
cout<<p[i]<<" ";
cout<<endl;
}
}
p.push_back(x);
dfs(x-1,count+1);
p.pop_back();
dfs(x-1,count+1);
}
int main(){
cin>>n>>m;
dfs(n,0);//降序选择小球
}