子集生成

子集生成

给定一个集合,枚举所有可能的子集。在这里的集合是{0,1,2...n-1}

1.增量构造法

感觉紫书上这段代码不是很好理解,画了一个图来辅助理解。这里的集合是{0,1,2...n-1},也可以看作是下标的集合,对任意集合,只要能输出它的下标的子集,也就能够输出该集合的子集。
这段代码还使用了定序的技巧,即所有元素是从小到大排列,在输出{1,2}后就不会输出{2,1}了,细细体会。
增量法的解答树共有\(2^n\)个结点,因为每个可能的A都对应一个结点,n元集合就有\(2^n\)个子集。

子集生成

代码:

void print_subset(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] :  0;          //确定当前元素的最小可能值
    for(int i = s; i < n; ++i){
        A[cur] = s;
        print_subset(n, A, cur+1);         //递归构造子集
    }
}
2.位向量法

构造一个位向量B[i],当B[i]=1,i在子集A中。通过位向量法的解答树能够理解,这里的解答树结点的结点总数为2047个,比增量构造法多,因为包含了部分解。

解答树的结点,我的理解是每次递归调用自身,就产生一个结点。

代码:

void print_subset(int n, int *B, int cur){
    if(cur == n){
        for(int i = 0; i < n; ++i)
            if(B[i]) printf("%d ", i);
        printf("\n");
        return;
    }
    B[cur] = 1;
    print_subset(n, B, cur+1);
    B[cur] = 0;
    print_subset(n, B, cur+1);
}

子集生成

3.位运算法

子集生成

代码:

void print_subset(int n, int i){
    for(int s = 0; s < n; ++s){
        if(i & (1<<s)) printf("%d ", s);
    printf("\n");
    }
}

for(int i = 0; i < (1<<n); ++i)
    print_subset(n, i);
上一篇:[LeetCode] (medium) 416. Partition Equal Subset Sum


下一篇:[Algorithm] Print All Subsets of a Set