题目大意:
有一个专门为了集合运算而设计的“集合栈”计算机。该机器有一个初始为空的栈,并且支持以下操作。
PUSH: 空集“{}” 入栈;
DUP: 出栈两个元素,然后把两者的并集入栈。
INTERSECT: 出栈两个集合,然后把两者的交集入栈。
ADD:出栈两个集合,然后把先出栈的集合加入到后出栈的集合中,把结果入栈。
每次操作结束后,输出栈顶集合的大小(即元素个数);
题目分析:
(这里我照搬算法竞赛入门经典第二版 (第116页),顺便膜拜一下汝佳大神)
本题的集合并不是简单的整数集合或者字符集合,而是集合的集合。为了方便起见,此处为每个不同的集合分配一个唯一的ID,则每个集合都可以表示成所包含元素的ID集合,这样就可以用STL的set<int>来表示了,而整个栈则是一个stack<int>;
(开始看可能不明白,STL中的内置集合操作set_union, set_intersection)
参考资料:
set_union: 点击打开链接
set_intersection: 点击打开链接
#include <iostream>
#include <cstdio>
#include <vector>
#include <map>
#include <stack>
#include <set>
#include <algorithm>
using namespace std;
typedef set<int> Set;
vector<Set> Setcache; //通过ID找到set集合;
map<Set, int> IDcache; // 通过set集合找到ID;
int ID(Set s){
if(!IDcache.count(s)){
Setcache.push_back(s);
IDcache[s] = Setcache.size()-1;
}
return IDcache[s];
}
#define ALL(x) x.begin(), x.end()
int main()
{
stack<int> s; //s中存放set集合的ID;
int T;
scanf("%d", &T);
while(T--){
int n; char op[10];
scanf("%d", &n);
for(int i = 0; i < n; ++i){
scanf("%s", 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_union(ALL(x1), ALL(x2), inserter(x, x.begin()));
if(op[0] == 'I') set_intersection(ALL(x1), ALL(x2), inserter(x, x.begin()));
if(op[0] == 'A') { x = x2; x.insert(ID(x1)); }
s.push(ID(x));
}
cout << Setcache[s.top()].size() << endl;
}
printf("***\n");
}
}