1. 程式人生 > >生成子集

生成子集

增量構造法

// {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;
}