富豪买项链问题


前言

第4次发csdn,心情依旧是有些许的激动


购买项链问题

超市的柜台上成列着n条项链,每条项链都由若干颗珠宝串成。为了方便起见,我们使用不同的小写英文字母来表达不同的珠宝种类。

一位富豪希望从这些中挑选一些购买。但是他有一个奇怪的要求:把所有购买的项链上的珠宝全部汇集到一起后,每种珠宝的的个数都必须为偶数。现在他希望知道,一共有多少种购买方案(什么都不买也算作一种方案)能够满足这个要求?

Input

第一行,包含一个整数1<=n<=40,表示项链个数
接下来n行,每行包含一个长度不超过105 的字符串,代表项链

Output

输出一行整数,表示在满足富豪要求的前提下,购买方案的数量。
(进阶版:输出每种符合要求珠宝组合)

Example

input:
4
abc
bac
cbabc
abca

output:
4

分解题目问题

购买项链的问题可以分解为四个步骤:
1、记录店内所有项链
2、对店内所有项链进行排列组合
3、对项链组合中珠宝进行统计
4、输出符合要求组合个数

第一步:记录店内所有项链

用string数组给店内所有珠宝确定位置
*以下为部分代码,文章最后将给出完整程序

int num,G=1;      //num珠宝数,G可选方案个数初始化为1(默认什么都不买)
    cin>>num;

    string STR[num];         //记录珠宝
    for (int j=0;j<num;j++){ //
        cin>>STR[j];         //
    }

第二步:解决如何选取项链组合

用二进制比特序列解决选取问题,1代表选择该项链,0代表不选
例:
1001代表选择第一个和第四个项链
故我们需要生成比特序列

string group(int Size,int Num){ //将十进制数Num转换成比特序列
                                //返回序列长度为Size
    string str;
    if(Num==0){
        for(int i=0;i<Size;i++){
            str='0'+str;
        }
        return str;
    }


    while(Num!=1){
        if(Num%2==1) str='1'+str;
        else str='0'+str;

        Num/=2;
    }
    str='1'+str;
    int size1,size2;
    size1=str.size();
    if(size1<Size){
        size2=Size-size1;
        for(int i=0;i<size2;i++){
            str='0'+str;
        }
    }

    return str;
}

通过遍历即可得出所有排列方式
*为了方便统计珠宝个数,我们将每种组合的珠宝连成一条新的项链
*以下为部分代码,文章最后将给出完整程序

    int Group;                  //总共组合方案个数
    Group=pow(2,num);           //2的num次方钟方案
    for (int i=1;i<Group;i++){  //遍历每一种方案
        string strG,strT;       //strG为本次的组合类型,strT为本次选择的珠宝
        strG=group(num,i);

        for(int k=0;k<num;k++){ //用二进制中1代表选择,0代表不选
            if(strG[k]=='1') strT+=STR[k];//将选择的项链连在一起变成新的项链
        }

第三步:对项链组合中珠宝进行统计

我们从所得 新的项链 的第一个珠宝开始,将它与剩下的珠宝进行对比,若珠宝种类相同则该珠宝数目加一,然后将该位置标记为零
将数过的珠宝标记为零,下一次可以直接跳过

	string strO;        //strO为对比参数,其值为“000...0”,零的个数为Size
    strO=group(Size,0);


     while (strT!=strO) {             //对新项链中每种珠宝进行计数
            string one;
            for(int r=0;r<Size;r++){     //从第一个珠宝开始,将其与之后的每个珠宝进行比较
                if(strT[r]=='0') continue;
                one=strT[r];
                int num3=0;
                for(int f=r;f<Size;f++){
                    if(one[0]==strT[f]){
                        num3++;
                        strT[f]='0';     //并将完成计数珠宝换成0
                    }
                    if((f+1)==Size  &&  num3%2!=0){//若新项链中某珠宝个数为奇数,则这种排列方式不符合要求,故跳过
                        flag=1;
                        goto part1;
                    }
                }
            }
        }

第四步:输出符合要求组合个数

    cout<<"Number of combinations : "<<G;  //输出可选个数

进阶版完整代码

#include <iostream>
#include <string>
#include<cmath>
using namespace std;

string group(int,int);    //二进制解决排列组合

int main()
{
    int num,G=1;      //num珠宝数,G可选方案个数初始化为1(默认什么都不买)
    cin>>num;

    string STR[num];         //记录珠宝
    for (int j=0;j<num;j++){ //
        cin>>STR[j];         //
    }



    int Group;                  //总共组合方案个数
    Group=pow(2,num);           //2的num次方钟方案
    for (int i=1;i<Group;i++){  //遍历每一种方案
        string strG,strT;       //strG为本次的组合类型,strT为本次选择的珠宝
        strG=group(num,i);

        for(int k=0;k<num;k++){ //用二进制中1代表选择,0代表不选
            if(strG[k]=='1') strT+=STR[k];//将选择的项链连在一起变成新的项链
        }
        int Size,flag=0;        //Size为组合成新项链的长度,flag为信标
        Size=strT.size();
        if(Size%2!=0) continue; //当项链长度为奇数时,必定不符合要求,故跳过
        else {
            string strO;        //strO为对比参数,其值为“000...0”,零的个数为Size
            strO=group(Size,0);


            while (strT!=strO) {             //对新项链中每种珠宝进行计数
                string one;
                for(int r=0;r<Size;r++){     //从第一个珠宝开始,将其与之后的每个珠宝进行比较
                    if(strT[r]=='0') continue;
                    one=strT[r];
                    int num3=0;
                    for(int f=r;f<Size;f++){
                        if(one[0]==strT[f]){
                            num3++;
                            strT[f]='0';     //并将完成计数珠宝换成0
                        }
                        if((f+1)==Size  &&  num3%2!=0){//若新项链中某珠宝个数为奇数,则这种排列方式不符合要求,故跳过
                            flag=1;
                            goto part1;
                        }
                    }
                }
            }
        }
    part1:
        G+=0;
    if(flag==0) { //若该种组合符合要求,则输出组合方式
        G++;

        cout<<"*******************************"<<endl;
        for(int k=0;k<num;k++){
            if(strG[k]=='1') cout<<STR[k]<<endl;
        }
        cout<<"*******************************"<<endl;

    }


    }
    cout<<"*******************************"<<endl;
    cout<<"Not buy"<<endl;
    cout<<"*******************************"<<endl;
    cout<<""<<endl;
    cout<<""<<endl;
    cout<<""<<endl;
    cout<<"Number of combinations : "<<G;  //输出可选个数

    return 0;
}

string group(int Size,int Num){

    string str;
    if(Num==0){
        for(int i=0;i<Size;i++){
            str='0'+str;
        }
        return str;
    }


    while(Num!=1){
        if(Num%2==1) str='1'+str;
        else str='0'+str;

        Num/=2;
    }
    str='1'+str;
    int size1,size2;
    size1=str.size();
    if(size1<Size){
        size2=Size-size1;
        for(int i=0;i<size2;i++){
            str='0'+str;
        }
    }

    return str;
}

在这里插入图片描述

以上为全部内容,祝你在学习道路上如履平地 ^_*

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值