1. 程式人生 > >求一個集合所有可能的子集

求一個集合所有可能的子集

【1】增量構造法

一次選出一個元素放到集合中

<pre name="code" class="cpp">#include<iostream>
#include<vector>
using namespace std;
const int MAX = 100;
int layer = -1; //遞迴層數
int count1 = 0;
void print_subset(int n, int *A, vector<int> &vi, int cur)
{
	cout << "layer:" << (++layer)<<endl;
	count1++;
	for (int i = 0; i < cur; i++)
	{
		cout << vi[A[i]] << " ";
	}
	cout << endl;

	int s = cur ? A[cur - 1] + 1 : 0;//使用定序的技巧,規定集合A中所有元素的編號從小到大排列,就不會將{1,2}按照{1,2}與{2,1}輸出兩次了
	for (int i = s; i < n; i++)
	{
		A[cur] = i;
		print_subset(n, A, vi, cur + 1);
	}
	layer--;
}

int main()
{
	int n,m,B[MAX];
	scanf("%d", &n);
	vector<int> vec;
	for (int i = 0; i < n; i++)
	{
		cin >> m;
		vec.push_back(m);
	}
	print_subset(n, B, vec, 0);
	cout << "number of set:" << count1 << endl;
	return 0;
}


【位向量法】
構造一個位向量B[i],其中當B[i]==1的時候i元素在子集a[]中,B[i]==0時不在子集a[]中。
#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;

const int MAX = 100;
int count1 = 0;
int layer = -1;
void fullCombination(vector<int> &vi,int n, int* B, int cur)
{
	cout<<"layer:"<<(++layer)<<endl;
	if (cur == n)
	{
		count1++;
		for (int i = 0; i < cur; i++)
		{
			if (B[i])
				cout << vi[i] << " "; // 列印當前集合
		}
		printf("\n");
		layer--;
		return;
	}
	B[cur] = 1; // 選第cur個元素
	fullCombination(vi,n, B, cur + 1);
	B[cur] = 0; // 不選第cur個元素
	fullCombination(vi, n, B, cur + 1);
	layer--;
}

int main()
{
	int B[MAX], n,m;
	vector<int>vec;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> m;
		vec.push_back(m);
	}
	fullCombination(vec,n, B, 0);
	cout << count1 << endl;
	return 0;
}

【3】二進位制法

#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;


void print_subset( int n, int s)//列印{0,1,2,...,n-1}的子集S
{
	for (int i = 0; i < n; i++)
	 if (s&(1 << i))printf("%d ", i);
	printf("\n");
}

int main()
{
	int n;
	cin >> n;
	
	for (int i = 0; i < (1 << n); i++)
		print_subset(n, i);
	return 0;
}