鼠假总结——two.STL模板

前言

背就完了,奥里给!

什么是STL

STL(Standard Template Library),意为标准模板库,是c++提供的一系列"容器",这里只说其中的vector,priority_queue,map,pair,set五种(实际为四种,因为pair在map的结构里),其中,除了 s e t set set外都有下标访问迭代器访问两种方法


Vectoe

又名变长数组,长度没有固定约束,随着需要的值而变化,在要用到多个数组或结构体时可	以用到.
需要用到头文件#include< vector>及 using namespace std;
基础定义为vector< typename> name;其中,typename可以是任何基本类型,如int、double、char、结构体等,也可以是容器

A.上网统计

题目描述
在一个网络系统中有N个用户1≤N≤1000、M次上网记录1≤M≤5000。每个用户可以自己注册一个用户名,每个用户名是一个只含小写字母的字符串。每个上网的账号每次上网都会浏览网页,网页名是一串只含小写字母的字符串,每次上网日志都会留下记录,现在请你统计一次上网日志中,每个用户浏览了多少个网页。(输出按照输入顺序输出)

输入格式
第一行N和M 第2行到第M+1行为M条上网日志,每行两个字符串,用空格隔开

输出格式
N个ID的上网记录,具体看样例

样例
样例输入
5 7
guomao wangyi
lifan tengxun
zhoushijian souhu
zhangshilin tengxun
guomao souhu
zhoushijian wangyi
liuyang bilibili

样例输出

guomao wangyi souhu
lifan tengxun
zhoushijian souhu wangyi
zhangshilin tengxun
liuyang bilibili

这道题可以用vector里面套vector,把每个ID的浏览记录也设为vector,用来储存所有浏览网页和长度

#include
#include
#include
#include
using namespace std;
struct ren{
	string ID;
	vector<string> WEB;
};
vector<ren> v;
int n,m;
int main()
{
	string id,web;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
    	cin>>id>>web;
    	bool flag=0;
    	for(int j=0;j<v.size();j++)
    	{
    		if(id==v[j].ID)//如果已有这个用户
    		{
    		    v[j].WEB.push_back(web);//在WEB里push网页名称
    		    flag=1;//已查找过
    			break;
			}
		}
		if(flag!=1)//新用户
		{
			ren now;
			now.ID=id;
			now.WEB.clear();
			now.WEB.push_back(web);
			v.push_back(now);
		}
	}
	for(vector<ren>::iterator it=v.begin();it!=v.end();it++)//迭代器访问
	{
		cout<<(*it).ID;
		for(vector<string>::iterator it1=(*it).WEB.begin();it1!=(*it).WEB.end();it1++)
		{
			cout<<" "<<*it1;//因为迭代器里储存的是地址,在前面加上*号才能取值
		}
		cout<<endl;
	}
	return 0;
}

priority_queue

优先队列,其本质是堆
需要用到头文件#include< queue>及 using namespace std;
	基础定义为queue< typename> name;其中,typename可以是任何基本类型,如int、double、char、结构体等,也可以是容器
	注意:和queue不一样的是,priority_queue没有front()和back(),而只能通过top()或pop()访问队首元素(也称为堆顶元素),也就是优先级最高的元素
初始定义为大根堆
priority_queue< int,vector< int>,less< int> >q;
若是小根堆
priority_queue< int,vector< int>,greater< int> >q;
注意:外层>要和里层分开,否则编译器会误认为是>>右移符号!

B. 有序表的最小和

题目描述
给出两个长度为 n 的有序表 A 和 B,在 A 和 B 中各任取一个元素,可以得到 n*n 个和,求这些和中最小的 n 个。

输入格式
第 1 行包含 1 个整数正 n(n≤400000)。 第 2 行与第 3 行分别有 n 个整数,各代表有序表 A 和 B。一行中的每两个整数之间用一个空格隔开,大小在长整型范围内,数据保证有序表单调递增。

输出格式
输出共 n 行,每行一个整数,第 i 行为第 i 小的和。 数据保证在 long long 范围内。

样例
【输入样例】

3
1 2 5
2 4 7
【输出样例】

3
4
5

此题是POJ2442 Sequence的简化版,但是n<=40000,所以 n 2 n^2 n2做法直接放弃,因为题目保证两个序表已经排好顺序,所以A[1]+B[1]一定为最小值,再枚举A[2]+b[1],A[3]+b[1]…A[n]+b[1],每次都取出最小值输出,再来移动B的值,使遍历的时间变为O(n+ l o g 2 log_2 log2n),此题还要用到重载运算符来返回最小值

#include
#include
#include
#include
using namespace std;
int a[4000005],b[4000005],c[400005];
struct ren{
	int id,zhi;
	bool operator<(const ren x) const { return zhi>x.zhi; }//大根堆是大的节点在前面,跟sort相反
};
priority_queue<ren> q;
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++) scanf("%d",&b[i]);
	for(int i=1;i<=n;i++)
	{
		c[i]=2;
		ren num;
		num.zhi=a[i]+b[1];
		num.id=i;
		q.push(num);
	}
	for(int i=1;i<=n;i++)
	{
		ren num=q.top();
		q.pop();
		printf("%d\n",num.zhi);
		num.zhi=a[num.id]+b[c[num.id]++];
		q.push(num);
	}
	return 0;
}

map+pair

map其实就是一种数组映射比如,“int a[100];”,就是定义了一个int到int的映射,而“a[5]=25;”是把5映射到25,他们是一一对应的,数组总是把int类型映射到其它基本类型,因为数组下标只能是int。但有时希望把string映射成一个int,数组就不方便了这时就可以使用map,它可以将任何基本类型(包括容器)映射到任何基本类型。
使用map,也必须加#include及using namespace std;。

D. 查字典

题目描述
gm英语非常不好,为了应对全国英文四级考试,他手里有一本英语字典,现在有很多单词要查。请编写程序帮助他快速找到要查的单词所在的页码。

输入格式
第一行1个整数N,N≤10000,表示字典中一共有多少单词。

接下来每两行1个单词,其中:第一行是长度≤100的字符串,表示这个单词,全是小写字母,单词不会重复。 第二行是1个整数,表示这个单词在字典中的页码。

接下来是一个整数M,M≤N,表示要查的单词数。 接下来M行,每行一个字符串,表示要查的单词,保证在字典中存在。

输出格式
M行,每行1个整数,表示第i个单词在字典中的页码。

样例
样例输入
2
scan
10
word
15
2
scan
word
样例输出
10
15

使用map,定义map,把每个字符串都“转化”为其页码,最后直接输出map[i]就行

#include
#include
#include
#include
using namespace std;
int n,m;
int ans[10005];
map<string,int> mp;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		ans[i]=0;
		int x;
		char zifu[105];
		cin>>zifu;
		scanf("%d",&x);
		mp[zifu]=x;
	}
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		char zifu[105];
		scanf("%s",zifu);
		ans[i]=mp[zifu];
	}
	for(int i=1;i<=m;i++)
	{
	    printf("%d\n",ans[i]);
	}
	return 0;
}

pair就是map的一种优化,可以把一个结构体或者两个需要的数直接存到map里面,减少编码时间
基础定义可以使用pair< t y p e n a m e 1 typename_1 typename1, t y p e n a m e 2 typename_2 typename2>

E. Let the Balloon Rise

题目描述
在ACM比赛中,你每解决一道题,你就可以获得一个气球,不同颜色的气球代表你解决了不同的问题。在GM同学参加的一场ACM比赛中,他发现场面上有N个气球,并熟练的说出了气球的颜色。

请你编写一个程序,找出气球数量最多的颜色。

输入格式
有多组样例输入。

每组样例第一行输入一个整数N (0 < N <= 1000) ,代表一共有N个气球。若N=0,则代表输入结束。

接下来N行每行输入一个不多于15个字母的字符串代表颜色。

输出格式
对于每组样例数据,在单独的一行内输出数量最多的那种颜色的气球。(数据保证输出是唯一的)

样例
样例输入
5
green
red
blue
red
red
3
pink
orange
pink
0
样例输出
red
pink

使用pair读入气球颜色,如果是每种颜色第一次出现,就insert(st,1),否则,该气球数量++

#include
#include
#include
using namespace std;
int n;
int main()
{
	while(scanf("%d",&n)&&n)
	{
	    map<string,int> mp;
		map<string,int>::iterator y;
        map<string,int>::iterator it;
		for(int i=0;i<n;i++)
		{
			char st[20];
			cin>>st;
		    it=mp.find(st);
		    if(it==mp.end())//如果没在map里面(size最多mp.end()-1),说明是第一次出现
		    {
		        mp.insert(pair<string,int>(st,1));
			}
			else{
				mp[st]++;
			}
		 }
		 int Max=0;
		 for(map<string,int>::iterator it=mp.begin();it!=mp.end();it++)
		 {
		 	if(it->second>Max)
		 	{
		 		Max=it->second;
		 		y=it;//用迭代器y来记录最大的气球的颜色和数量
			 }
		  }
		  cout<<y->first<<endl;//只输出颜色,y->first代表输出键,键也就是存入量(被映射量)
	}
	return 0;
}

set

可以理解为一个自动排序和去重的集合,需要用到头文件
#include< set>,using namespace std;
定义为set< typename> name;
用insert()来插入元素,size()来查询集合元素个数,用find()来查找迭代器的地址
只能用迭代器来完成以上操作

F. 题海战

题目描述
某信息学奥赛教练经验丰富,他的内部题库有 m 道题。他有 n 个学生,第 i 个学生已经做过p[i]道题。由于马上要进行noip考试,该教练准备举行 k 场比赛和训练。每场比赛或训练都会有一些他的学生参加,但是如何选题令他非常烦恼。对于每场比赛,他要保证所出的题没有任何一道已有任何一个学生做过;而对于每场训练,他要保证所出的所有题都被每一个参赛学生做过。

输入格式
第1行2个正整数n和m,表示学生数和题库中的题目总量。

第2~n+1行,先是1个正整数p,然后p个整数表示第i个学生的做题记录(可以重复做同一道题)。

第n+2行,1个正整数k,表示要举行比赛和训练的总场数(可能有学生重复报名)。

接下来的k行,每行的第1个整数type表示是训练或者比赛(1为训练,0为比赛)。第二个数q表示参赛学生数,然后q个正整数表示参赛学生编号。每一行的两个数之间有一个空格。

输出格式
共k行,每行表示本次训练或比赛可选的最多题目(由小到大排序,中间用一个空格隔开,如果没有输出一个空行)。

样例
样例输入
5 10
2 3 7
1 3
2 4 7
3 3 6 10
7 1 2 3 4 7 8 9
6
0 3 3 4 5
0 3 1 3 4
1 2 1 3
0 1 5
1 1 2
1 2 3 5
样例输出
5
1 2 5 8 9
7
5 6 10
3
4 7

用集合来判断是否有做或没做过一道题,在训练中,如果没做过,erase(i),反之,在比赛中如果做过,erase(i)

#include
#include
#include
using namespace std;
set<int> quanji,stu[10005];
int n,m,k,fff;
int main()
{
	scanf("%d%d",&n,&m);
	int num,x;
	for(int i=1;i<=n;i++)
	{
		stu[i].clear();
		scanf("%d",&num);
		for(int j=0;j<num;j++)
		{
			scanf("%d",&x);
			stu[i].insert(x);
		}
	}
	for(int i=1;i<=m;i++)
	{
		quanji.insert(i);
	}
	scanf("%d",&k);
	int bi,xue;
	for(int i=0;i<k;i++)
	{
		set<int> ans=quanji;
		scanf("%d%d",&bi,&xue);
		if(bi==1)
		{
			for(int j=0;j<xue;j++)
			{
		   	 scanf("%d",&fff);
			 for(set<int>::iterator it=ans.begin();it!=ans.end();)
			 {
			 	if(stu[fff].find(*it)==stu[fff].end())
			 	{
			 		ans.erase(it ++);
				 }
				 else{
				 	it++;
				 }
			 }
			} 
			 for(set<int>::iterator it=ans.begin();it!=ans.end();it++)
			 {
			 	cout<<*it<<" ";
			 }
			 printf("\n");
		}
		else{
	    for(int j=0;j<xue;j++)
		{
		 scanf("%d",&fff);
		 for(set<int>::iterator it=ans.begin();it!=ans.end();)
		 {
		 	if(stu[fff].find(*it)!=stu[fff].end())//判断每一道题学生是否做过
		 	{
		 		ans.erase(it ++);
			}
			 else{
				it++;
			 }
		 }
		} 
		 for(set<int>::iterator it=ans.begin();it!=ans.end();it++)
		 {
			cout<<*it<<" ";
		 }
		 printf("\n");
           }
   }
   return 0;
}

总结

在使用迭代器时要注意没有it

bool operator<(const ren x) const { return zhi>x.zhi; }

bool operator<(const ren x,const ren y)
{
if(x.shi!=y.shi)
{
return x.shi>y.shi;
}
return x.id>y.id;
}

这才算完全掌握
要继续加油啊!

你可能感兴趣的:(STL)