生成子集

1 生成子集

1.1 含义

给定一个集合,枚举它所有可能的子集。

比如给定集合{1,2,3},应该输出:

{}

{1}

{2}

{1, 2}

{3}

{1, 3}

{2, 3}

{1, 2, 3}

1.2 增量构造法

增量构造法,每次选择一个元素放到集合中,每次操作的结果即是一个子集。

递归操作,每次向当前集合中添加一个比当前集合中最大的元素大1的数。

代码:

from __future__ import print_function

def print_subset(n, lst, cur):
    for i in range(cur):
        print(lst[i]+1, end='')
    print()
    if cur:
        s = lst[cur - 1] + 1
    else:
        s = 0
    for i in range(s, n):
        lst[cur] = i
        print_subset1(n, lst, cur+1)

1.3 位向量法

构造位向量(可理解为构造一个数组),该向量中的每一位置可以取0值或者1值,0和1分别代表该位置上对应的值是否在集合中。如向量为[1, 0, 0, 1],其第1和4位上有1,所以该向量表示的集合为{1, 4}。

思路:

如果需要用向量来表示集合,那么需要保证向量的每一种变化能够刚好覆盖集合的每一种可能性。

对n求子集,构造长度为n的向量,每一位可以代表取或者不取该位置的值,共有2^n中可能。

代码为:

from __future__ import print_function

def print_subset(n, lst, cur):
    if cur == n:
        for i in range(n):
            if lst[i]:
                print(i+1, end='')
        print()
    else:
        lst[cur] = 0
        print_subset(n, lst, cur+1)
        lst[cur] = 1
        print_subset(n, lst, cur+1)

1.4 二进制法

我们可以使用二进制法来表示子集。对于n求子集,其子集有2^n个(包括空集),比如n = 4,其有16个子集,这16个子集用二进制可以表示成:

0->0000->{}

1->0001->{1}

2->0010->{2}

3->0011->{1,2}

4->0100->{3}

5->0101->{1,3}

...

15->1111->{1,2,3,4}

思路:

求n的子集,可以依次处理1到2^n - 1之间的每一个数,每个数取出它二进制表示中的1的位置,以此表示该数对应的集合。比如5,二进制表示的后四位为0101,其在第1和第3位处有1,那么,其代表的集合为{1, 3}。使用位运算中与(&)操作,可以方便的求出二进制某位置上是否为1。

代码:

from __future__ import print_function
s = 1
n = 4
while s < (1 << n):  # 依次遍历1到2^n - 1之间的每一个数
    for i in range(n):  # 每一个数使用&操作判断该位置上是否有1,有打印或者保存起来
        if s & (1 << i):
            print(i+1, end='')
    print()
    s += 1

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-03 22:38:48

生成子集的相关文章

(算法初步学习)蛮力法解决生成子集问题

关于蛮力法求生成子集问题 对于算法分析中的问题我已经不想对自己说什么了,到了大三了,竟然还是小白.对生成子集问题我研究了一下午,最后终于想通了.思路:   1.利用<math.h> 头文件中的pow(x,y)函数来求得2的n次方,作为外循环.2.然后写一个将10进制数转换为2进制数的函数(当然,C中有专门的转换进制的函数在<stdlib.h>中,但是,他转换下来  5不是0101而是101,这就导致需要分开判断,所以不用itoa函数).如下:conversation(int n,i

构造增量法生成子集

题意: 生成 1~n 集合的子集, 先按元素从小到大再按字典序排列输出 分析: 所谓构造增量法, 就是每次都输出当前数组的元素, 然后再给当前数组最大元素一个增量, 看是否仍然在集合内, 如果在就把他继续放进数组, 输出. 这种方法不需要显式确认递归边界, 如果无法添加元素, 自然就不会再递归了. 数据结构我选用了string , 因为字典序比较容易排序出来. #include <bits/stdc++.h> using namespace std; string ans[1 <<

使用位生成子集

定义: 对于任何一个集合B,只要A 包含于 B 那么A即是B的子集,每个集合子集个数为2^n个(n为集合中元素的个数) 考虑数2^n,它的第n位是1(第一位是第0位).它总共包含2^n 个数字. n=0   2^n=1  空集 n=1 2^1=2  空集+只有一个元素的集合 假设以下n=2 n=2 总共有4个元素 集合元素个数 位表示法 0 0 1 01   和 10 2 11 由此有,我们需要枚举2^n次,每次检查生成数字的位数是否为1,如果有1的,说明应该取对应的元素.代码如下. void

生成子集 (增量构造法)

使用增量构造法可以构造出升序数组arr的不重复子集,并且按字典序排序 #include<bits/stdc++.h> using namespace std; int arr[16]; inline void print_subset(int *index, int cur, int n)///cur值这里可以理解为在这个堆栈层子集的集合数 { for(int i=0; i<cur; i++) {printf("%d ", arr[index[i]]);} if(cu

subsets之给定一个数列&amp;生成该数列所有的子集&amp;升序

(1)先假设数列的元素不重复,例如[ 4, 2 ,3 ],可知总共有2^3=8个子集,在加一个空集: (2)对数列排序,可方便生成子集升序[2, 3 , 4]: (3)每个子集对应一个二进制值,0-空集 1-> (2) 2->(3) 3->(2,3) -- 7->(2,3,4),二进制数1的位置对应数列中相应位置的数.遍历一遍可得结果. (4)进一步,如果数列有重复怎么办?例如[ 2 , 3 ,3 ] ,似乎一下子复杂起来,因为上述方法生成了很多相同的子序列.没错,相同的子序列,不

子集生成——暴力求解,枚举

子集生成:给定一个集合,枚举它所有可能的子集.(简单起见,这里假设集合中没有重复元素) 一.增量构造法 思路:一次选出一个元素放到集合中. Code: void print_subset1(int n, int *A, int cur) {//增量构造法 for(int i=0;i<cur;++i) printf("%d ",A[i]); printf("\n"); int s=cur ? A[cur-1]+1 :0;//确定当前元素的最小可能值 for(in

特征选择常用算法综述

特征选择的一般过程: 1.生成子集:搜索特征子集,为评价函数提供特征子集 2.评价函数:评价特征子集的好坏 3.停止准则:与评价函数相关,一般是阈值,评价函数达到一定标准后就可停止搜索 4.验证过程:在验证数据集上验证选出来的特征子集的有效性 1.生成子集 搜索算法有 完全搜索.启发式搜索.随机搜索 三大类. (1)完全搜索 <1>宽搜(Breadth First Search):时间复杂度高,不实用 <2>分支界限搜索(Branch and Bound):其实就是宽搜加上深度的限

Subsets II

Given a collection of integers that might contain duplicates, nums, return all possible subsets. Note: Elements in a subset must be in non-descending order. The solution set must not contain duplicate subsets. For example, If nums = [1,2,2], a soluti

2.1.4 Healthy Holsteins 健康的好斯坦奶牛

2.1.4 Healthy Holsteins 健康的好斯坦奶牛 一.题目描述 农民JOHN以拥有世界上最健康的奶牛为傲.他知道每种饲料中所包含的牛所需的最低的维他命量是多少.请你帮助农夫喂养他的牛,以保持它们的健康,使喂给牛的饲料的种数最少. 给出牛所需的最低的维他命量,输出喂给牛需要哪些种类的饲料,且所需的饲料剂量最少. 维他命量以整数表示,每种饲料最多只能对牛使用一次,数据保证存在解. PROGRAM NAME: holstein INPUT FORMAT 第1 行:一个整数V(1<=V<