题目:
小明很喜欢选数字,现在小明得到 𝑛 个数,他想得到从 𝑛 个数里面选取 𝑘 个数的所有方案,由于小明的作业很多,现在没有时间解决这个问题,聪明的你可以帮助小明解决这个问题吗?
输入数据
输入包括两行数据,第一行包括两个数 𝑛(1≤𝑛<25) , 𝑘(1≤𝑘≤𝑚𝑖𝑛(𝑛,19)), 表示数列数的个数以及要从数列里面选取数的个数。
第二行 𝑛 个数表示该数列的 𝑛 个数 (0<𝑎𝑖≤100,𝑎𝑖 表示数列里面的数, 𝑎𝑖 可能有重复)。
(两个数之间用空格分开)。
输出数据
按字典序输出所有的方案(格式参照样例)
数据范围
对于 10% 的数据, 1≤𝑛≤5 , 𝑘≤𝑛
对于 50% 的数据, 1≤𝑛≤10 , 𝑘≤𝑛
对于 100% 的数据, 1≤𝑛≤24 ,𝑘≤min(n,19)
样例:
输入:
4 2
1 1 2 3
输出:
1 1
1 2
1 3
2 3
数据范围
从 (1,1,2,3)4 个数字里面选 2 个,有 (1,1),(1,2),(1,3),(2,3) 四种选法。
解题技巧:
为了保证输出的字典序,先对给出的数字进行排序,如果有相同的数字,那么排序后会挨在一起。
此时如果直接套用从 𝑛 个数中选择 𝑚 个数的递归,由于 𝑎𝑖 中有相同的数字,因此会出现完全重复的选择。
为了不出现重复的选择,我们规定如果挨着的两个数字相同,假如前一个没有选,后一个也不能选。
这样需要用一个 𝑏𝑜𝑜𝑙 数组记录选或未选的状态。剩下的逻辑就同 𝑛 个数中选 𝑚 个数一样了。按照之前的方法递归处理即可。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,k,nums[26],sel[26];
bool flag[26];
void DFS(int index,int min){
if(index==k){
for(int i=0;i<k;i++)
cout<<sel[i]<<" ";
cout<<endl;
return;
}
for(int i=min;i<=n;i++){
if(nums[i]==nums[i-1]&&!flag[i-1])
continue;
sel[index]=nums[i];
flag[i]=true;
DFS(index+1,i+1);
flag[i]=false;
}
}
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>nums[i];
sort(nums+1,nums+n+1);
DFS(0,1);
return 0;
}
注:原文来自51NOD,为@小罐头甜编辑