说实话 这是一道让我十分费解的题, 最大的问题在于不知道用什么样的数据结构或容器来存储这些set,
最后实在想不通了, 只能上网找例程来看... 一开始居然还看不懂, 到后来才逐渐理解起来
就是可以用map来把各种各样的set各自一一映射到一个数值, 相当于用数值来编码各种形态的set
这样就充分利用了map的优点, 正如其名——映射
比如从某个数字开始, 为set建立映射, mp[set1]==0 说明set1未建立映射(第一次出现)
以后每次对一个集合set进行insert的时候都要insert它的映射的值
这样以后就可以用集合里的一个个数值来判断两个集合是否是同一个了
AC代码如下
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <map>
using namespace std;
const int MAXN = 30;
typedef long long LL;
/*
uva 12096 【难点】
关键 : 仍用set<>表示集合, 但是关键是附加一个map< set<int>,int > 来映射不同的集合到不同的数值上
*/
vector< set<int> > s; // 注意stack存的还是set<>
map< set<int>,int > mp;
int setNum = 1000; // 从数字1000开始为set建立映射, mp[set1]==0 说明set1未建立映射(第一次出现)
// 以后每次对一个集合set进行insert的时候都要insert它的映射的值
// 这样以后就可以用集合里的一个个数值来判断两个集合是否是同一个了
set<int> Pop(){
set<int> top = s.back();
s.erase(s.end()-1);
return top;
}
int main(){
// freopen("input2.txt","r",stdin);
int Case,N;
string cmd;
scanf("%d",&Case);
while( Case-- ){
scanf("%d",&N);
int topsize = 0;
set<int> top;
s.clear();
mp.clear();
mp[top] = setNum++; // 首先为空集合建立编号
while( N-- ){
cin >> cmd;
set<int> t1,t2,res;
set<int>::iterator it;
if( cmd=="PUSH" ){
set<int> newset;
s.push_back(newset); // newset是空集合, 初始化时映射到了第一个编号
topsize = 0;
}else if( cmd=="DUP" ){
top = s.back();
s.push_back(top);
topsize = top.size();
}else if( cmd=="INTERSECT" ){
t1 = Pop();
t2 = Pop();
set_intersection(t1.begin(),t1.end(),t2.begin(),t2.end(),inserter(res,res.begin()));
s.push_back(res);
topsize = res.size();
}else if( cmd=="UNION" ){
t1 = Pop();
t2 = Pop();
set_union(t1.begin(),t1.end(),t2.begin(),t2.end(),inserter(res,res.begin()));
s.push_back(res);
topsize = res.size();
}else if( cmd=="ADD" ){ // 关键
t1 = Pop();
t2 = Pop();
if( mp[t1]==0 ){ // t1未建立映射
mp[t1] = setNum++;
}
t2.insert(mp[t1]);
s.push_back(t2);
topsize = t2.size();
}
cout << topsize << endl;
}
cout << "***" << endl;
}
return 0;
}