题目链接
解题思路
用map给每个集合分配一个编号,刚好利用了map里的元素不允许重复和count函数可以查询某个元素有没有出现过。用vector把集合存起来,通过编号可以在vector里提取出相应的集合,在栈里操作编号就很方便。
这道题就妙在它是集合的集合,我们为每个不同的集合分配一个ID,那每个集合就可以表示成所包含元素的ID的集合,就可以用set<int>
了。
笔记
-
set求a与b的并集存在c中:
set_union(a.begin(), a.end(), b.begin(), b.end(), inserter(c, c.begin() );
inserter(c,c.begin())为插入迭代器,此函数接受第二个参数,这个参数必须是一个指向给定容器的迭代器。元素将被插入到给定迭代器所表示的元素之前。
交集用 set_intersection
参考链接 -
map可太好用了,就是我之前一直不知道它的正确用法【哭泣】
map<key, value> m;
它只能从键(key)到值(value)不能从值到键
比如map<string, int> m; m["july"] = 2;
可以,m[2] = "july";
就不行
心得
我在紫书上看代码以为我懂的透透的了,但是自己一些编译都过不了。不要抄代码,懂了意思之后自己写写试试。像这种有点乱的题理清楚之后再动手写。
代码
#include <cstdio>
#include <iostream>
#include <iterator>
#include <cstring>
#include <vector>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
using namespace std;
typedef set<int> Set;
vector<Set> v;
map<Set, int> m;
int getID(Set s)
{
if (m.count(s)) return m[s];
v.push_back(s);
return m[s] = v.size() - 1;
}
stack<int> s;
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
//仔细一想就能发现vector和map不需要清空
//v.clear();
//m.clear();
int n;
scanf("%d", &n);
while (n--)
{
string op;
cin >> op;
if (op[0] == 'P')
{
s.push(getID(Set()));
}
else if (op[0] == 'D')
{
s.push(s.top());
}
else
{
Set x1 = v[s.top()]; s.pop();
Set x2 = v[s.top()]; s.pop();
Set c = Set();
if (op[0] == 'U')
{
set_union(x1.begin(), x1.end(), x2.begin(), x2.end(), inserter(c, c.begin()));
s.push(getID(c));
}
else if (op[0] == 'I')
{
set_intersection(x1.begin(), x1.end(), x2.begin(), x2.end(), inserter(c, c.begin()));
s.push(getID(c));
}
else
{
x2.insert(getID(x1));
s.push(getID(x2));
}
}
printf("%d\n", v[s.top()].size());
}
printf("***\n");
}
return 0;
}