[UVA1209]集合栈计算机 The SetStack Computer 题解(栈 详解)

集合栈计算机 The SetStack Computer - 洛谷

Background from Wikipedia: “Set theory is a branch of mathematics created principally by the German mathematician Georg Cantor at the end of the 19th century. Initially controversial, set theory has come to play the role of a foundational theory in modern mathematics, in the sense of a theory invoked to justify assumptions made in mathematics concerning the existence of mathematical objects (such as numbers or functions) and their properties. Formal versions of set theory also have a foundational role to play as specifying a theoretical ideal of mathematical rigor in proofs.”

Given this importance of sets, being the basis of mathematics, a set of eccentric theorist set off to construct a supercomputer operating on sets instead of numbers. The initial SetStack Alpha is under construction, and they need you to simulate it in order to verify the operation of the prototype. The computer operates on a single stack of sets, which is initially empty. After each operation, the cardinality of the topmost set on the stack is output.

The cardinality of a set S is denoted |S| and is the number of elements in S. The instruction set of the SetStack Alpha is PUSH, DUP, UNION, INTERSECT, and ADD.

• PUSH will push the empty set {} on the stack.

• DUP will duplicate the topmost set (pop the stack, and then push that set on the stack twice).

• UNION will pop the stack twice and then push the union of the two sets on the stack.

• INTERSECT will pop the stack twice and then push the intersection of the two sets on the stack. • ADD will pop the stack twice, add the first set to the second one, and then push the resulting set on the stack.

For illustration purposes, assume that the topmost element of the stack is

A = {{}, {{}}}

and that the next one is

B = {{}, {{{}}}}

For these sets, we have |A| = 2 and |B| = 2. Then:

• UNION would result in the set {{}, {{}}, {{{}}}}. The output is 3.

• INTERSECT would result in the set {{}}. The output is 1.

• ADD would result in the set {{}, {{{}}}, {{},{{}}}}. The output is 3.

Input

An integer 0 ≤ T ≤ 5 on the first line gives the cardinality of the set of test cases. The first line of each test case contains the number of operations 0 ≤ N ≤ 2000. Then follow N lines each containing one of the five commands. It is guaranteed that the SetStack computer can execute all the commands in the sequence without ever popping an empty stack.

Output

For each operation specified in the input, there will be one line of output consisting of a single integer. This integer is the cardinality of the topmost element of the stack after the corresponding command has executed. After each test case there will be a line with ‘***’ (three asterisks).

Sample Input

2

9

PUSH

DUP

ADD

PUSH

ADD

DUP

ADD

DUP

UNION

5

PUSH

PUSH

ADD

PUSH

INTERSECT

Sample Output

0

0

1

0

1

1

2

2

2

***

0

0

1

0

0

***

题意翻译

有一个专门为了集合运算而设计的“集合栈”计算机。该机器有一个初始为空的栈,并且支持以下操作:

PUSH:将空集{}入栈

DUP:把当前栈顶元素复制一份后再入栈

UNION:出栈两个集合,然后把两者的并集入栈

INTERSECTION:出栈两个集合,然后把两者的交集入栈

ADD:出栈两个集合,然后把先出栈的集合加入到后出栈的集合中,把结果入栈

每次操作后,输出栈顶集合的大小(即元素个数)

题解

栈的定义

栈(stack)是限定仅在表尾进行插入或者删除的线性表。对于栈来说,表尾端称为栈顶(top),表头端称为栈低(bottom)。不含元素的空表称为空栈。因为栈限定在表尾进行插入或者删除,所以栈又被称为后进先出的线性表(简称LIFO:Last in, First out.结构)。

栈的基本操作

栈的基本操作主要有:栈的初始化判空判满取栈顶元素在栈顶进行插入和删除。在栈顶插入元素称为入栈,在栈顶删除元素称为出栈

stack<int> s;        //创建一个空的 stack 对象。
empty()              //判断是否为空栈
push()               //入栈
pop()                //出栈
top()                //返回栈顶元素
size()               //返回栈中元素的数目

分析

本题的集合并不是简单的整数集合或者字符串集合,而是集合的集合。为了方便起见,此处为每个不同的集合分配一个唯一的ID,则每个集合都可以表示为所包含元素ID的集合,这样就可以用STL的set<int>来表示了,而整个栈则是一个stack<int>。

typedef set<int> Set;
map<Set,int> IDcache;			//把集合映射成ID
vector<Set> Setcache;			//根据ID取集合

// 查找给定集合x的ID。如果找到分配一个新的ID
int ID(Set x){
	if(IDcache.count(x)){
		return IDcache[x];
	}
	Setcache.push_back(x);		//添加新集合
	return IDcache[x]=Setcache.size()-1; 
} 

对任意集合s(类型是上面定义的Set),IDcache[s]就是它的ID,而Setcache[IDcache[s]]就是s本身。下面的ALL和INS是两个宏:

#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())

分别表示“所有的内容”以及“插入迭代器”,具体作用可以从代码中推断出来,有兴趣的读者可以查阅STL文档以了解更详细的信息。主程序如下,请读者注意STL内置的集合操作(如set_union和set_intersection)。

stack<int> s;        //题目中的栈 
int n;
cin>>n;
for(int i=0;i<n;i++){
	string op;
	cin>>op;
	if(op[0]=='P'){
		s.push(ID(Set()));
	}else if(op[0]=='D'){
		s.push(s.top());
	}else{
		Set x1=Setcache[s.top()];
		s.pop();
		Set x2=Setcache[s.top()];
		s.pop;
		Set x;
		if(op[0]=='U'){
			set_nuion(ALL(x1),ALL(x2),INS(x));
		}
		if(op[0]=='I'){
			set_intersection(ALL(x1),ALL(x2),INS(x));
		}
		if(op[0]=='A'){
			x=x2;
			x.insert(ID(x1)); 
		}
		s.push(ID(x));
	}
	cout<<Setcache[s.top()].size()<<endl;
} 

本题极为重要!!!

正确答案

#include<iostream>
#include<stack>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())//插入迭代器,用于后面的取并集、交集以及合并后返回一个set<int>
using namespace std;
map<set<int>,int> IDdata;//将集合映射成数
vector< set<int> > setdata;//可以理解为集合的检索表,用于对集合ID的分配与对已知ID的集合的查询
int ID(set<int> x) { //查找给定集合x的ID。若找不到,分配一个新ID。
	if(IDdata.count(x))return IDdata[x];
	setdata.push_back(x);
	return IDdata[x]=setdata.size()-1;
}
int main() {
	int T;
	cin>>T;
	while(T) {
		T--;
		stack<int>s;
		int n;
		cin>>n;
		for(int i=1; i<=n; i++) {
			string point;
			cin>>point;
			if(point=="PUSH")
				s.push(ID(set<int>()));
			else if(point=="DUP")
				s.push(s.top());
			else {
				set<int> x1=setdata[s.top()];
				s.pop();
				set<int> x2=setdata[s.top()];
				s.pop();
				set<int> x;
				if(point=="UNION")set_union(ALL(x1),ALL(x2),INS(x));
				else if(point=="INTERSECT")set_intersection(ALL(x1),ALL(x2),INS(x));
				else if(point=="ADD") {
					x=x2;
					x.insert(ID(x1));
				}
				s.push(ID(x));
			}
			cout<<setdata[s.top()].size()<<endl;
		}
		cout<<"***"<<endl;
	}
	return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

古谷彻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值