UVA - 12096:The SetStack Computer

这篇博客探讨了在处理无限集合时如何进行编码,通过紫书提供的方法,利用STL中的map对集合进行哈希编码。文章重点介绍了如何巧妙地使用set和map进行集合操作,如并集、交集和差集,并展示了C++代码实现。同时,指出了在switch语句中定义局部变量的注意事项,以及STL中map对set哈希的支持特性。
摘要由CSDN通过智能技术生成

题目描述很简单,难点在于如何对集合进行编码,因为是无限的,好像没有一个方向进行编码。
紫书给的题解十分巧妙:给新出现的集合进行编码
的确,我们没有必要为所有可能出现的集合编码后再开始,我们就可以简单的根据出现的次序分配一个映射值即可,这个值只要能够代表这个集合并且不发生碰撞。
另一个巧妙的点是STL中的map竟然支持从对set的哈希,这个也太神奇了,虽然不明白是怎么做的,可能要看源码才能理解。
代码如下:

需要注意的一点是在switch语句中的case语句后面不能直接声明局部变量,要放在大括号里面,形成一个局部变量。其原因是如果直接定义的话,其他case语句也是可以看到这个变量的,但是如果不执行那个定义的case语句,就会导致变量声明却没有定义。原因在于switch其实就是一种奇特的goto

#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <stack>
#include <string>
#include <algorithm>
#include <iterator>

using namespace std;
using Set = set<int>;

class SetHash {
    vector<Set> num2set;    //保存num到set的映射
    map<Set, int> set2num;  //保存set到num的映射
public:
    int operator ()(Set s); //获取一个set的hash值
    Set operator ()(int num);//获取一个hash值为num的set
    int getSize(int num) const;
};

int SetHash::operator()(Set s) {
    if (!set2num.count(s)) {
        set2num[s] = num2set.size();
        num2set.push_back(s);
        return num2set.size() - 1;
    } else {
        return set2num[s];
    }
}

Set SetHash::operator()(int num) {
    return num2set[num];
}

int SetHash::getSize(int num) const {
    return num2set[num].size();
}

stack<int> stk;     //用于保存集合栈

int main() {
    ios::sync_with_stdio(false);
    int T, n;
    string cmd;
    SetHash setHash;
    cin >> T;
    while (T--) {
        cin >> n;
        while (n--) {
            cin >> cmd;
            if (cmd[0] == 'P') stk.push(setHash(Set()));
            else if (cmd[0] == 'D') stk.push(stk.top());
            else {
                Set a = setHash(stk.top()); stk.pop();
                Set b = setHash(stk.top()); stk.pop();
                switch (cmd[0]) {
                    case 'U':
                        b.insert(a.begin(), a.end());
                        stk.push(setHash(b));
                        break;
                    case 'I':
                    {
                        Set c;
                        set_intersection(a.begin(), a.end(), b.begin(), b.end(), inserter(c, c.begin()));
                        stk.push(setHash(c));
                        break;
                    }
                    case 'A':
                        b.insert(setHash(a));
                        stk.push(setHash(b));
                        break;
                }
//
            }
            cout << setHash.getSize(stk.top()) << "\n";
        }
        cout << "***\n";
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值