The SetStack Computer

也可以查看我的个人博客
题目链接

题意:现有一个栈,有五种操作:
1、PUSH操作:
添加一个空的集合{}到这个栈中
2、DUP操作:
将栈顶复制一份再添加到这个栈中
3、UNION操作:
从栈中弹出两个集合,再将这两个集合的并集加入到栈中
4、INTERSECT操作:
从栈中弹出两个集合,再将这两个集合的交集加入到栈中
5、ADD操作:
从栈中弹出两个集合,并把先弹出的集合添加到后弹出的集合中,再将后弹出的集合添加到栈中。

以上每一次操作完成之后都输出一下栈顶集合的大小,即元素个数,数据输入保证合法。

思路:可以利用STL里的set、map、stack、vector来解决。
我们可以用STL里的set来代替这里的集合,但是我们网stack里存集合的时候不能直接放set,因为这样行不通,这样的话需要set存的类型还是set,这是不允许的。
我们可以为每一个set做一个编号,通过map可以快速找到一个set对应的编号,这样的话,我们再用vector保存所有的set,这样就可以通过编号来解决这题了。

坑点:集合的互异性,即这个题中说的集合中是不能

代码:

#include <map>
#include <set>
#include <stack>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef set < int > SET;

string op;
int n , id;
stack < int > s;
vector < SET > v;
map < SET , int > ID;

inline void init()//初始化
{
    id = 0;
    v.clear();
    ID.clear();
    while(!s.empty()) s.pop();
}

int getID(SET a)//通过一个SET直接找到对应的编号
{
    if(ID.count(a)) return ID[a];//如果存在
    ID[a] = id ++;//对其进行编号
    v.push_back(a);//添加到vector中
    return id - 1;//返回编号
}
int main(void)
{
    int T;
    cin >> T;
    while(T --)
    {
        scanf("%d" , &n);
        
        init();
        
        while(n --)
        {
            cin >> op;
            
            if(op == "PUSH")
            {
                s.push(getID(SET()));
            }
            
            else if(op == "DUP")
            {
                s.push(s.top());
            }
            
            else if(op == "UNION")
            {
                SET a = v[s.top()] ; s.pop();
                SET b = v[s.top()] ; s.pop();
                SET c;
                
                //这里采用了c++内置的函数,可以将a和b的并集放入c中
                set_union(a.begin() , a.end() , b.begin() , b.end() , inserter(c , c.begin()));
                
                s.push(getID(c));
            }
            
            else if(op == "INTERSECT")
            {
                SET a = v[s.top()] ; s.pop();
                SET b = v[s.top()] ; s.pop();
                SET c;
                
                //交集
                set_intersection(a.begin() , a.end() , b.begin() , b.end() , inserter(c , c.begin()));
                s.push(getID(c));
            }
            
            else
            {
                SET a = v[s.top()] ; s.pop();
                SET b = v[s.top()] ; s.pop();
                
                b.insert(getID(a));
                
                s.push(getID(b));
            }
            
            cout << v[s.top()].size() << endl;
        }
        
        printf("***\n");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值