集合划分问题(c++输出集合数目以及不同的集合)

问题: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;
}

谢谢浏览,如果对你有用点个赞呗!

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在编译原理中,First集合指的是文法中每个非终结符号所能推导出的所有终结符号的集合。计算一个文法中每个非终结符号的First集合是语法分析中的一个重要过程,可以用于LL(1)语法分析器的构建。 First集合的计算规则如下: 1. 如果X是终结符,则First(X) = {X}; 2. 如果X是非终结符,且存在产生式X → a...,其中a是终结符,则将a加入First(X)中; 3. 如果X是非终结符,且存在产生式X → Y...,其中Y是非终结符,则将First(Y)中不含空串的所有符号加入First(X)中; 4. 如果X是非终结符,且存在产生式X → Y...,其中Y是非终结符,且First(Y)中包含空串,则将First(Y)中不含空串的符号加入First(X)中,并将继续处理产生式Y → b...,直到找到一个非空的First集合。 下面是一个用C++实现计算First集合的例子代码: ```cpp #include <iostream> #include <map> #include <vector> #include <set> using namespace std; // 定义产生式结构体 struct Production { char left; string right; }; // 定义非终结符集合、产生式集合和First集合映射表 set<char> nonTerminals; vector<Production> productions; map<char, set<char>> first; // 计算某个符号的First集合 void calcFirst(char sym) { for (auto& prod : productions) { if (prod.left == sym) { if (islower(prod.right[0])) { first[sym].insert(prod.right[0]); } else if (nonTerminals.count(prod.right[0])) { calcFirst(prod.right[0]); for (auto& c : first[prod.right[0]]) { if (c != '#') { first[sym].insert(c); } } } else if (prod.right[0] == '#') { first[sym].insert('#'); } } } } int main() { // 初始化非终结符集合和产生式集合 nonTerminals = {'S', 'A', 'B'}; productions = {{'S', "AB"}, {'S', "BC"}, {'A', "a"}, {'A', "#"}, {'B', "b"}, {'B', "#"}, {'C', "c"}}; // 计算每个非终结符的First集合 for (auto& sym : nonTerminals) { calcFirst(sym); } // 输出每个非终结符的First集合 for (auto& sym : nonTerminals) { cout << "First(" << sym << ") = { "; for (auto& c : first[sym]) { cout << c << " "; } cout << "}" << endl; } return 0; } ``` 在这个例子中,我们首先定义了一个非终结符集合和产生式集合,并用一个结构体表示每个产生式。然后,我们定义了一个map来存储每个非终结符的First集合。最后,我们通过calcFirst函数来计算每个非终结符的First集合,并输出结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值