https://vjudge.net/problem/UVA-12096
stack+其他容器的综合应用
想要用好STL工具写好程序,一定要能将题目中的操作整理抽象出来,一定要思路清晰。
题目分析:
首先题目SetStack computer就告诉我们可以使用set和stack…
本题是对集合的集合操作,也就是说我们的操作是取并集交集等集合操作,我们操作的元素是集合,所以并不是简单实用stack和set就能实现的。
然后根据题目,外层容器用栈stack实现,栈的元素用set实现。
为了实现题目要求的输出栈顶元素大小,也就是栈顶的集合的元素大小,设置了一个栈stack<int> s和vector<Set> Setcache,然后用map<Set,int> IDcache形成他们之间的映射。
就是用vector保存了每个出现过的不一样的集合,然后给其分配一个唯一ID,map用来保存这种映射关系。对于集合的出入栈操作就用集合对应的编号实现了,比如栈{}对应0,{{}}对应1,栈里有两个集合是{} {{}},那么我们的栈中实际存的是0 1。
更加详细的解释:对于每个元素,它有唯一的编号,比如{}对应0,{{}}对应1。之前说过,栈中的每个元素又都是集合,因此如果这个栈的元素是{},对应的Set是空集;如果这个元素是{{}},那么对应的Set是{0},编号为1;如果是{{},{{}}}那么对应的Set是{0,1},这时的Set是一个新Set,它又会有一个自己的编号比如2。
这道题的难点在ADD操作上。
实例分析:
操作 | 栈顶元素个数 | 当前栈的状态(右侧为栈顶) |
---|---|---|
PUSH | 0 | {} |
DUP | 0 | {} {} |
ADD | 1 | {{}} |
PUSH | 0 | {{}} {} |
ADD | 1 | {{{}}} |
DUP | 1 | {{{}}} {{{}}} |
ADD | 2 | {{{}},{{{}}}} |
DUP | 2 | {{{}},{{{}}}} {{{}},{{{}}}} |
UNION | 2 | {{{}},{{{}}}} |
下面紫书AC代码:
PS:关于一些语法的解释:
Set() 应该是类似于构造函数的用法,生成一个空集
set_union、set_intersection这两个函数的作用和参数就是字面意思。
具体见参考手册搜索对应函数名
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;
}
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
int main()
{
stack<int> s; //题目中的栈
int n,t;
cin>>t;
while(t--){
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_union (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;
}
cout<<"***"<<endl;
}
return 0;
}