基础数据结构-UVa12096 集合栈计算机 紫书代码解析

思想

代码是紫书上的代码,本文主要写一些对书上知识的理解,希望能够帮助大家理解这方面的知识。本题的基本解题思路就是利用Stl里自带的进栈、出栈,求交集并集的函数来做题。但是这里涉及的问题是如何来保存集合,并对其进行操作。紫书上给出的思路是利用map,来将集合映射成整数编号,给每一个集合分配一个整数编号(编写一个ID函数实现),通过对编号的操作,就能实现对集合的操作。就像在学校里,如果要将一个班的同学按照身高排成队,不需要把所有同学都叫到一起挨个比较身高来排,而只需要有一个全班同学身高表,按照身高表将同学提前排好,然后以学号为索引让每个同学对号入座即可。其实作者的另一篇题解(Unix Is命令题解)也是借鉴了紫书上这道题提出的这个思想。此外,这里的宏定义也是一个妙用。

代码及注释

#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
#include<vector>
#define ALL(x) x.begin(),x.end()            //迭代器 (从头到尾) 
#define INS(x) inserter(x,x.begin())        //这里是插入迭代器,insert是插入的意思。写这两个宏只是为了后面少写代码而已 
using namespace std;
typedef set<int>Set;                        //利用typedef函数给set<int>取一个新的名字;
map<Set,int> IDcache;                       //用map来联系集合和它的编号;
vector<Set> Setcache;                       //存真的集合(因为要涉及求交集并集等,要用到Stl的集合有关的函数。 
int ID(Set x){
	if(IDcache.count(x)) return IDcache[x];   //当已有ID时直接取ID
	Setcache.push_back(x);                    //将集合加到真的集合里面(Setcache保证里面所存集合都是有ID的) 
  return IDcache[x]=Setcache.size()-1;      //将上一行加进去的那个集合确定编号,同时将编号作为该ID函数的返回值 
} 
stack<int> s;
int main(){
	
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
  
  int T;
  cin>>T;
  while(T--){
  int n;
	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));                           //操作统统用的是ID 
		}
		cout<<Setcache[s.top()].size()<<endl;   //输出栈顶集合的元素的个数 
	}
	cout<<"***"<<endl;
  }
	return 0;
} 

注意紫书上的代码有不全的地方,第一是没有头文件,本文代码加上了。第二是原题是多组数据输入,本文代码用变量T写了while循环来支持多组数据输入(注意每组之间用“***”隔开)。

发布了50 篇原创文章 · 获赞 7 · 访问量 1156

猜你喜欢

转载自blog.csdn.net/numb_ac/article/details/103050227