输出所有组合(二进制枚举)

输出所有组合(二进制枚举)


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 2n1行。

我们可以先找出所有的排列组合,再对组合进行特定排序,就可以输出答案了。那怎么枚举所有的排列组合呢?

由于排列组合的原理,故每次输出的个数为 2 n − 1 2^{n-1} 2n1n为输入的字符串长度。所以就可以利用二进制表示的方式来求解,即给所有输出方式进行编号,那么从1到 2 n − 1 2^{n-1} 2n1 中每个数的二进制表示中,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 
    *   ┃        ┣┓
    *    ┃        ┏┛
    *     ┗┓┓┏━┳┓┏┛ + + + +
    *    ┃┫┫ ┃┫┫
    *    ┗┻┛ ┗┻┛+ + + +
    */
}



最后感谢小伙伴们的学习噢~

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__Wedream__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值