集合划分问题

n个元素的集合{1,2,…,n}可以划分若干非空子集。例如,当n=4时,集合{1,2,3,4}可以划分为15个不同的非空子集如下:

{{1},{2},{3},{4}} {{1,3},{2,4}}

{{1,2},{3},{4}} {{1,4},{2,3}}

{{1,3},{2},{4}} {{1,2,3},{4}}

{{1,4},{2},{3}} {{1,2,4},{3}}

{{2,3},{1},{4}} {{1,3,4},{2}}

{{2,4},{1},{3}} {{2,3,4},{1}}

{{3,4},{1},{2}} {{1,2,3,4}}

{{1,2},{3,4}}

给定正整数n,计算出n个元素的集合{1,2,,…,n}可以划分为多少个不同的非空子集。

输出集合数目及不同的集合。

测试数据为5和6

输入

5

输出

划分为1个数组的情况有:
{{1,2,3,4,5}}
划分为2个数组的情况有:
{{1,2,3,4},{5}}
{{1,2,3,5},{4}}
{{1,2,5,4},{3}}
{{1,5,4,3},{2}}
{{1,5,4},{2,3}}
{{1,2,5},{4,3}}
{{1,5,3},{2,4}}
{{1,5},{2,4,3}}
{{1,2,3},{5,4}}
{{1,2,4},{5,3}}
{{1,4,3},{2,5}}
{{1,4},{2,5,3}}
{{1,2},{5,4,3}}
{{1,3},{2,5,4}}
{{1},{2,5,4,3}}
划分为3个数组的情况有:
{{1,2,3},{4},{5}}
{{1,2,4},{3},{5}}
{{1,4,3},{2},{5}}
{{1,4},{2,3},{5}}
{{1,2},{4,3},{5}}
{{1,3},{2,4},{5}}
{{1},{2,4,3},{5}}
{{1,2,5},{3},{4}}
{{1,5,3},{2},{4}}
{{1,5},{2,3},{4}}
{{1,5,4},{2},{3}}
{{1,5},{2,4},{3}}
{{1,5},{2},{3,4}}
{{1,2},{5,3},{4}}
{{1,3},{2,5},{4}}
{{1},{2,5,3},{4}}
{{1,4},{2,5},{3}}
{{1},{2,5,4},{3}}
{{1},{2,5},{3,4}}
{{1,2},{3},{5,4}}
{{1,3},{2},{5,4}}
{{1},{2,3},{5,4}}
{{1,4},{2},{3,5}}
{{1},{2,4},{3,5}}
{{1},{2},{3,5,4}}
划分为4个数组的情况有:
{{1,2},{3},{4},{5}}
{{1,3},{2},{4},{5}}
{{1},{2,3},{4},{5}}
{{1,4},{2},{3},{5}}
{{1},{2,4},{3},{5}}
{{1},{2},{3,4},{5}}
{{1,5},{2},{3},{4}}
{{1},{2,5},{3},{4}}
{{1},{2},{3,5},{4}}
{{1},{2},{3},{4,5}}
划分为5个数组的情况有:
{{1},{2},{3},{4},{5}}
总共有52种情况

代码

#include <iostream>
using namespace std;
int a[101][101],b[101]={0};//a里面存储集合元素,b存储集合元素个数 
int n,sum=0,M;//sum记录总数,M存储最原先要划分的集合个数 
int tongji(int c,int m)//b为数字个数,m为所划分集合个数 
{
	int i,j;
	if(m==1||c==m)//当满足条件m等于1或c和m相等时输出 
	{
		cout<<'{';//输出左边最外面的花括号 
		if(m==1)//当m为1时 
		{
			cout<<'{';//输出{
			for(i=1;i<=c;)//把1到c的所有数字当作第一组输出 
			{
				if(i!=1) cout<<',';
				cout<<i++;
			}
			for(i=0;i<b[1];)//合并数组存储的第一组的元素
			{
				cout<<',';
				cout<<a[1][i++];
			}	
			cout<<'}';//输出}
			for(j=2;j<=M;j++)//输出a数组存储的几个集合 
			{
				cout<<',';//输出逗号分隔集合
				cout<<'{';//输出{
				for(i=0;i<b[j];)
				{
					if(i!=0) cout<<',';
					cout<<a[j][i++];
				}
				cout<<'}';//输出}
			}
			
		}
		else//c==m的情况下
		{
			for(j=1;j<=M;j++)//把1-c分别作为1-c组集合的元素 
			{
				if(j!=1)  cout<<',';//输出逗号分隔集合,第一组不用 
				cout<<'{';//输出{
				if(j<=c) cout<<j;//把j作为j组集合的元素输出 
				for(i=0;i<b[j];)//输出a数组存储的几个集合
				{
					if(j<=m||i!=0) cout<<',';
					cout<<a[j][i++];
				}
				cout<<'}';//输出}
			}
		}
		cout<<'}'<<endl;//输出右边最外面的花括号,换行 
		sum++;//总数加一 
	}
	else
	{
		a[m][b[m]++]=c;
		tongji(c-1,m-1);
		b[m]--;//还原为原来的数组 
		for(i=1;i<=m;i++)//让数字c存储在第1到第m个集合,再递归 
		{
			a[i][b[i]++]=c; //让数字c存储在第i个集合
			tongji(c-1,m); //继续递归调用自身 
			b[i]--;//还原为原来的数组
		}
	}
}
int main()
{
	int n,i;
	cin>>n;//输入n 
	for(i=1;i<=n;i++)//按划分数组个数来划分种类 
	{
		cout<<"划分为"<<i<<"个数组的情况有:"<<endl; 
		M=i;//用M存储最原先要划分的集合个数 
		tongji(n,i);//套用函数,划分为i个集合
	}
	cout<<"总共有"<<sum<<"种情况"<<endl;//输出总数 
}

上一篇:2022.2.12 开学后的一些事


下一篇:处理字符串并排序