问题: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
运行结果附图
本人运用了vector和queue两个头文件,具体实现如下:
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
//算法关键:F(n-1,m-1)+F(n,m-1)*m
//定义一个类型为vector<vector<int> >的队列,再用vector<vector<int>>存储vector<int>
queue<vector<vector<int> > > func(int n)
{
queue<vector<vector<int> > > q;
vector<int> v;//定义了一个整型元素的向量
v.push_back(1);//在v的最后一个向量后插入一个元素,其值为1
vector<vector<int> > vv;//定义二维vector
vv.push_back(v);//在vv的最后一个vector<int>向量后插入v
q.push(vv);//q.push()从已有元素后面增加元素
for (int i = 2; i <= n; i++)//循环并插入数字
{
int len = q.size();//q.size()输出现有元素的个数
while (len--)//此循环用来对每个现有元素进行插入
{
//M.front()显示第一个元素, M.pop()清除第一个元素,把q的数据转移出来处理,
//并且删除q中的数据,方便处理完数组的插入
vector<vector<int> > vv = q.front();
q.pop();
//下面的for循环相当于F(n-1,m-1),元素插入到已有集合中
for (int j = 0; j < vv.size(); j++)
{
vector<vector<int> > t = vv;
t[j].push_back(i);//在t[j]的第一个元素(从第0个算起)位置插入数值i
q.push(t);//在q已有元素后面增加元素t
}
//下面部分相当于F(n,m-1)*m,元素形成新的集合插入队列中
vector<int> v;
v.push_back(i);//在v的第一个元素(从第0个算起)位置插入数值i
vv.push_back(v);//在vv的第一个元素(从第0个算起)位置插入v
q.push(vv);//在q已有元素后面增加元素vv
}
}
return q;//返回队列
}
int main()
{
//用户输入所求值的集合划分
int n;
cin >> n;
//定义队列
auto q = func(n);
int cnt = 0;
cout << "所有集合如下:" << endl;
while (!q.empty())
{
cnt++;
cout << cnt << ": ";
const auto vv = q.front();
q.pop();
/*
//const auto& 当只想读取range中元素时,使用const auto&,
如:for(const auto & x:range), 它不会进行拷贝,也不会修改range
c++中for(auto count : counts) 意思是将 counts 容器中的每一个元素
从前往后枚举出来,并用 count 来表示,类似于Java中的 for each 语句
*/
cout << "{";
for (const auto& v : vv)
{
int sign = 1;
cout << "{";
for (auto i : v)
{
if (sign == 1)
sign--;
else
cout << ",";
cout << i;
}
cout << "}";
}
cout << "}" << endl;
}
cout << "共有" << cnt << "个不同的非空子集";
return 0;
}
谢谢浏览,如果对你有用点个赞呗!