输出所有组合(二进制枚举)
Problem Description
题目:输入一个字符串,输出该字符串中字符的所有组合。举个例子,如果输入abc,它的组合有a、b、c、ab、ac、bc、abc。
采用递归的方法来实现所有组合的输出。
Input
输入一个串长n和字符串,n<10。
字符串不含重复元素。
Output
输出该字符串中字符的所有组合,并在每个组合前标示序号。
注意:为了输出的组合有序而便于OJ系统评判,约定无论输入的初始字符串是什么顺序的,最后输出都按元素升序进行挑选的组合。
先输出长度为1,而后长度为2,……。长度相等时,字母小的排在前面输出。
Sample Input
3 bac
Sample Output
1 a
2 b
3 c
4 ab
5 ac
6 bc
7 abc
Hint
提示陆续写上来,不着急,先自行思考和讨论……
Solution
题目说要用递归的解法,但是我们从另外一个角度来思考一下。
题目给出长度为n的字符串,那对于字符串的n个字符,我们有两种情况,就是选或者不选,因此排列组合有 2 n 2^{n} 2n钟情况。题目的输出不包含空串,因此我们还要减一,所以我们要输出 2 n − 1 2^{n}-1 2n−1行。
我们可以先找出所有的排列组合,再对组合进行特定排序,就可以输出答案了。那怎么枚举所有的排列组合呢?
由于排列组合的原理,故每次输出的个数为 2 n − 1 2^{n-1} 2n−1个,n为输入的字符串长度。所以就可以利用二进制表示的方式来求解,即给所有输出方式进行编号,那么从1到 2 n − 1 2^{n-1} 2n−1 中每个数的二进制表示中,1的位置即为要输出的字符串中的位置。
下面我们来举个例子
例如,对于 “bac” 来说:
(我们首先悄眯眯地把"bac"排序成"abc",即最小字典序,s[0]对应a,s[1]对应b,s[2]对应c)
那么每个二进制数有以下对应关系:
0 0 1 --> a (s[0]被选)
0 1 0 --> b (s[1]被选)
0 1 1 --> ab (s[0]和s[1]被选)
1 0 0 --> c (s[2]被选)
1 0 1 --> ac (s[0]和s[2]被选)
1 1 0 --> bc (s[1]和s[2]被选)
1 1 1 --> abc (s[0]、s[1]和s[2]都被选)
以上刚好把7种排列组合全枚举出来了,不过还不符合输出的顺序。
那么我们再定义一个cmp函数,将排序规则写在里面,在sort的时候调用cmp函数,排列组合就能排列成指定的顺序了(详情请参考代码)。
Code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
int n,m,T;
string s[1025];
char ss[26];
bool cmp(string a,string b) //定义string的排序规则
{
int la=a.length();
int lb=b.length();
if(la!=lb)return la<lb;
return a<b;
}
void solve()
{
cin>>n>>ss;
sort(ss,ss+n); //先将输入的字符串进行排序,如"bac"先排序成"abc"
for(int i=1; i<(1<<n); i++) //二进制枚举所有排列情况
{
for(int j=0; j<n; j++)
{
if((i>>j)&1)
s[i]+=ss[j];
}
}
sort(s+1,s+(1<<n),cmp); //按cmp定义的顺序进行排序
for(int i=1; i<(1<<n); i++)
cout<<i<<' '<<s[i]<<endl;
}
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
solve();
/*
*
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████+
* ◥██◤ ◥██◤ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃ + + + +Code is far away from
* ┃ ┃ + bug with the animal protecting
* ┃ ┗━━━┓ 神兽保佑,代码无bug
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*/
}
最后感谢小伙伴们的学习噢~
![](https://img-blog.csdnimg.cn/20200830095925823.png#pic_center)