例题5-5 集合栈计算机(The Set Stack Computer,ACM/ICPC NWERC 2006,UVa12096)
欢迎访问我的Uva题解目录哦 https://blog.****.net/richenyunqi/article/details/81149109
题目描述
题意解析
有一个专门为了集合运算而设计的“集合栈”计算机。该机器有一个初始为空的栈,并且支持以下操作:
- PUSH:空集“{}”入栈。
- DUP:把当前栈顶元素复制一份后再入栈。
- UNION:出栈两个集合,然后把二者的并集入栈。
- INTERSECT:出栈两个集合,然后把二者的交集入栈。
- ADD:出栈两个集合,然后把先出栈的集合加入到后出栈的集合中,把结果入栈。
每次操作后,输出栈顶集合的大小(即元素个数)。
输入不超过2000个操作,并且保证操作均能顺利进行(不需要对空栈执行出栈操作)。
算法设计
参考了《算法竞赛与入门经典》书上的算法:
本题的集合并不是简单的整数集合或者字符串集合,而是集合的集合。为了方便起见此处为每个不同的集合分配一个唯一的ID,则每个集合都可以表示成所包含元素的ID集合,这样就可以用STL的set来表示了,而整个栈则是一个stack<int>。
该算法实际上就是将涉及到的集合存储到一个vector
中,然后用vector
中的下标来指代某一集合。用一个set<int>
来表示一个集合,set<int>
中的元素即为前面所说的vector
的下标。
C++代码
#include<bits/stdc++.h>
using namespace std;
vector<set<int>>sets;//存储集合
map<set<int>,int>idCache;//集合与sets下标的映射关系
int ID(set<int>&s){//获取集合在sets中的下标
if(idCache.find(s)==idCache.end()){//没有这一集合,分配一个新的id
idCache[s]=sets.size();
sets.push_back(s);
}
return idCache[s];
}
int main(){
int T,N;
cin>>T;
while(T--){
cin>>N;
stack<int>s;
string input;
while(N--){
cin>>input;
if(input=="PUSH"){
set<int>temp;
s.push(ID(temp));
}else if(input=="DUP"){
s.push(ID(sets[s.top()]));
}else{
int id1=s.top();
s.pop();
int id2=s.top();
s.pop();
set<int>result;
if(input=="UNION"){
set_union(sets[id1].begin(),sets[id1].end(),sets[id2].begin(),sets[id2].end(),inserter(result,result.begin()));
}else if(input=="INTERSECT"){
set_intersection(sets[id1].begin(),sets[id1].end(),sets[id2].begin(),sets[id2].end(),inserter(result,result.begin()));
}else if(input=="ADD"){
result=sets[id2];
result.insert(ID(sets[id1]));
}
s.push(ID(result));
}
cout<<sets[s.top()].size()<<endl;
}
cout<<"***"<<endl;
}
return 0;
}