子集生成算法

      问题:  给定一个正整数,列出{1, 2, ···,n}的所有子集

    朋友问我这个问题,一时无法作答,才发现,没有受过系统的计算机专业教育,对于我来讲,是个短板,于是,查看书籍,才在离散数学上找到了子集生成算法的基本介绍。
      算法介绍:
      若集合S包含n个元素x1, x2, ···, xn, 则用一种简介的表示S的子集的方法是,把它表示成由0和 1组成的串,其中,若xk 属于S,则串中的第K个元素为1,否则为0. 例如,若n = 3, 则8(= 23)个串及其对应的子集如下所示:
    000       空集                              100           {x1 }
    001      {x3}                                101           {x1, x3}
    010      {x2}                                110           {x1, x2}
    011      {x2, x3}                                 111          {x1,  x2,  x3}
    通过这个列表,可以看出如何按照上面的次序来生成这些0-1串:先寻找最右边的0,把它变成1,然后把它右边的所有数字都变成0.

 
  给定一个 正整数n和一个由0-1组成的串a1a2···an,计算下某一个子集所对应的0-1串的算法伪代码如下:
   步骤1  (初始化)
          K = n
   步骤2  (寻找最右边的0)
          while(k >= 1且ak=1)
                k = k -1
         endwhile
   步骤3(如果存在0, 则形成后续串)
        if(k >= 1)
   步骤3.1(把最右边的0变成1)
              ak = 1
    步骤3.2(把ak右边的所有1变成0)
             for j=k+1 to n
                   aj = 0
             Endfor
   步骤3.3(输出新子集)
            打印
       otherwise
   步骤3.4(不存在0,也就是没有下一个串)
            打印全集
        endif


  下面是问题的实现代码,C++:
   
#include <iostream>
using namespace std;

int subset(int *pSet, int *pMask, int nlen)
{
    if(pSet == NULL)
        return -1;
    if(pMask == NULL)
        return -1;
    int k = nlen;
   
    //找到最右边的0
    while(k >= 1)
    {
        if(pMask[k-1] == 1)
            k -= 1;
        else
            break;
    }

    //pMask串中找到最右边0位,把它变成1,
    //并把它右边的所有数字都变成0;
    if(k >= 1)
    {
        //打印当前的子集
        cout << "{ " ;
        for(int i=0; i<nlen; i++)
        {
            if(pMask[i] == 1 )
                cout << pSet[i] << " ";
        }
        cout << "}" << endl;
        pMask[k-1] = 1;
        for(i= k; i<nlen; i++)
        {
            pMask[i] = 0;
        }

        subset(pSet, pMask, nlen);
    }
    //整个pMask串都为1,找不到0位,
    else
    {
        cout << "{ ";
        for(int i=0; i<nlen; i++)   
            cout << pSet[i] << " ";
        cout << " }" << endl;
    }
   
    return 0;
}


int main(void)
{
    int n;
    cout << "Please input the numbr n-> " ;
    cin >> n;

    int *pSet = new int[n];
    int *pMask = new int[n];
    if(pSet == NULL)
        return -1;
    if(pMask == NULL)
        return -1;

    for(int i=0; i<n; i++)
        pSet[i] = i+1;
    for(i=0; i<n; i++)
        pMask[i] = 0;

    subset(pSet, pMask, n);
   
    if(pSet != NULL)
        delete[] pSet;
    if(pMask != NULL)
        delete[] pMask;

    return 0;
}


运行结果如下:
Please input the number n-> 3
{  }
{ 3 }
{ 2 }
{ 2 3 }
{ 1 }
{ 1 3 }
{ 1 2 }
{ 1 2 3 }
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值