• 枚举所有子集的三种算法详解-《算法入门经典》


    方法一:增量构造法

      理解递归必须得理解函数到底是做什么的。

    #include<cstdio>
    
    void print_subset(int n,int *a,int cur)  //print_subset的功能是打印集合{0,1,...,n-1}的cur个元素的子集,并且目前a数组中已经存储了要打印的集合 
    {
        printf("{ ");
        for (int i=0;i<cur;i++) printf("%d ",a[i]);
        printf("}
    ");
        int mi=cur?a[cur-1]+1:0;  //利用字典序避免重复打印 
        for (int i=mi;i<n;i++)  //枚举下一位可以添加什么元素 
        {
            a[cur]=i;
            print_subset(n,a,cur+1);  //递归打印cur+1个元素的子集 
        }
    }
    
    int main()
    {
        int n;
        int a[10]={};
        scanf("%d",&n);
        print_subset(n,a,0); //初始时a中存储了0个元素的子集,开始递归打印 
        return 0;
    }

    方法二:位向量法

      枚举每一位选或者不选,复杂度比方法一略高但更好理解,因为与输出全排列思路差不多,满n位就输出。

    #include<cstdio>
    
    int a[10];
    
    void print_subset(int n,int *b,int cur)  //确定第cur位选或者不选 
    {
        if (cur==n)  //如果确定好了n位,打印结果 
        {
            printf("{ ");
            for (int i=0;i<n;i++)
                if (b[i]) printf("%d ",a[i]);
            printf("}
    ");
        } 
        else
        {
            b[cur]=1;  //这一位选 
            print_subset(n,b,cur+1);  //递归下一位 
            b[cur]=0;  //这一位不选 
            print_subset(n,b,cur+1);  //递归下一位 
        }
    }
    
    int main()
    {
        int n;
        int b[10]={};
        scanf("%d",&n);
        for (int i=0;i<n;i++) a[i]=i;
        print_subset(n,b,0);
        return 0;
    }

      缺点是输出不是按照字典序。

    方法三:二进制法

      稍加思考就会发现,方法二其实与二进制是对应的。

    #include<cstdio>
    
    int a[10];
    
    void print_subset(int n,int b)  //n位的集合,b状态打印 
    {
        printf("{ ");
        for (int i=0;i<n;i++)
            if (b&(1<<i)) printf("%d ",a[i]);
        printf("}
    ");
    }
    
    void p_s(int n)
    {
        for (int i=0;i<(1<<n);i++) print_subset(n,i);  //枚举所有状态 
    }
    
    int main()
    {
        int n;
        scanf("%d",&n);
        for (int i=0;i<n;i++) a[i]=i;
        p_s(n);
        return 0;
    }

      这个方法优点就是代码简单。

    注意:以上三种方法输出顺序不同。

  • 相关阅读:
    钉钉C# 使用数据接口要注意的问题
    两个比较快的DNS
    钉钉考勤组信息
    Sqlserver直接附加数据库和设置sa密码
    SQL Server 2016 附加数据库提示创建文件失败如何解决
    FastJson用法
    钉钉开发平台文档
    Sqlserver脚本创建登录名密码
    string 与 stringbuilder效率相差很大
    C# RichTextBox插入带颜色数据
  • 原文地址:https://www.cnblogs.com/itlqs/p/5720784.html
Copyright © 2020-2023  润新知