生成子集

版权声明:本文为博主原创文章,欢迎转载,转载时请以超链接形式标明文章原始出处。 https://blog.csdn.net/lilongsy/article/details/83579871

增量构造法

// {0~n-1}的所有子集:增量构造法
// Rujia Liu
#include<cstdio>
using namespace std;

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]+1 : 0; // 确定当前元素的最小可能值
  // 定序
  for(int i = s; i < n; i++) {
	// 一次选出一个元素放到集合中
	// 如果无法继续添加元素,自然就不会再递归了
    A[cur] = i;
    print_subset(n, A, cur+1); // 递归构造子集
  }
}

int A[10];
int main() {
  int n;
  scanf("%d", &n);
  print_subset(n, A, 0);
  return 0;
}

输入输出

位向量法

构造一个位向量B[i],而不是直接构造子集A本身,其中B[i]=1,当且仅当i在子集A中。
必须当“所有元素是否选择”全部确定完毕后才是一个完整的子集,因此仍然像以前那样当if(cur == n)成立时才输出。

// {0~n-1}的所有子集:位向量法
// Rujia Liu
#include<cstdio>
using namespace std;

void print_subset(int n, int* B, int cur) {
  if(cur == n) {
    for(int i = 0; i < cur; i++)
      if(B[i]) printf("%d ", i); // 打印当前集合
    printf("\n");
    return;
  }
  B[cur] = 1; // 选第cur个元素
  print_subset(n, B, cur+1);
  B[cur] = 0; // 不选第cur个元素
  print_subset(n, B, cur+1);
}

int B[10];
int main() {
  int n;
  scanf("%d", &n);
  print_subset(5, B, 0);
  return 0;
}

输入输出

二进制法

用二进制来表示{0, 1, 2,…,n-1}的子集S:从右往左第i位(各位从0开始编号)表示元素i是否在集合S中。

// {0~n-1}的所有子集:二进制法
// Rujia Liu
#include<cstdio>
using namespace std;

// 打印{0, 1, 2, ..., n-1}的子集S
void print_subset(int n, int s) {
  for(int i = 0; i < n; i++)
	// 这里利用了C语言“非0值都为真”的规定
    if(s&(1<<i)) printf("%d ", i);
  printf("\n");
}

int main() {
  int n;
  scanf("%d", &n);
  // 枚举各子集所对应的编码 0, 1, 2, ..., 2^n-1
  for(int i = 0; i < (1<<n); i++)
    print_subset(n, i);
  return 0;
}

猜你喜欢

转载自blog.csdn.net/lilongsy/article/details/83579871