望各位小牛,小犇,中牛,中犇,大牛,大犇,神牛,神犇给予鼓励
小小蒟蒻在此先%%%%%%%%%%%%%%%%%拜大神
一.什么是队列(queue)
1.简介
队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO—first in first out)线性表。
2.数组实现
队列可以用数组Q[1…m]来存储,数组的上界m即是队列所容许的最大容量。在队列的运算中需设两个指针:head,队头指针,指向实际队头元素;tail,队尾指针,指向实际队尾元素的下一个位置。一般情况下,两个指针的初值设为0,这时队列为空,没有元素。数组定义Q[1…10]。Q(i) i=3,4,5,6,7,8。头指针head=2,尾指针tail=8。队列中拥有的元素个数为:L=tail-head。现要让排头的元素出队,则需将头指针加1。即head=head+1这时头指针向上移动一个位置,指向Q(3),表示Q(3)已出队。如果想让一个新元素入队,则需尾指针向上移动一个位置。即tail=tail+1这时Q(9)入队。当队尾已经处理在最上面时,即tail=10,如果还要执行入队操作,则要发生"上溢",但实际上队列中还有三个空位置,所以这种溢出称为"假溢出"。
克服假溢出的方法有两种。一种是将队列中的所有元素均向低地址区移动,显然这种方法是很浪费时间的;另一种方法是将数组存储区看成是一个首尾相接的环形区域。当存放到n地址后,下一个地址就"翻转"为1。在结构上采用这种技巧来存储的队列称为循环队列。
队列和栈一样只允许在断点处插入和删除元素。
循环队的入队算法如下:
1、tail=tail+1;
2、若tail=n+1,则tail=1;
3、若head=tail,即尾指针与头指针重合了,表示元素已装满队列,则作上溢出错处理;
4、否则,Q(tail)=X,结束(X为新入出元素)。
队列和栈一样,有着非常广泛的应用。
注意:(1)有时候队列中还会设置表头结点,就是在队头的前面还有一个结点,这个结点的数据域为空,但是指针域指向队头元素。
(2)另外,上面的计算还可以利用下面给出的公式cq.rear=(cq.front+1)/max;
当有表头结点时,公式变为cq.rear=(cq.front+1)/(max+1)。
3.链表实现
在队列的形成过程中,可以利用线性链表的原理,来生成一个队列。
基于链表的队列,要动态创建和删除节点,效率较低,但是可以动态增长。
队列采用的FIFO(first in first out),新元素(等待进入队列的元素)总是被插入到链表的尾部,而读取的时候总是从链表的头部开始读取。每次读取一个元素,释放一个元素。所谓的动态创建,动态释放。因而也不存在溢出等问题。由于链表由结构体间接而成,遍历也方便。
4.基本运算
(1)初始化队列:queue<数据类型> q;,初始条件:队q 不存在。操作结果:构造了一个空队;
(2)入队操作:q.push(元素名) ,初始条件: 队q 存在。操作结果: 对已存在的队列q,插入一个元素x 到队尾,队发生变化;
(3)出队操作: q.pop() ,初始条件: 队q 存在且非空,操作结果: 删除队首元素,并返回其值,队发生变化;
(4)读队头元素:q.front() ,初始条件: 队q 存在且非空,操作结果: 读队头元素,并返回其值,队不变;
(5)判队空操作:q.empty() ,初始条件: 队q 存在,操作结果: 若q 为空队则返回为1,否则返回为0。
(6)读长度元素:q.size() ,初始条件: 队q 存在且非空,操作结果: 返回q队列的个数;
(4)读队尾元素:q.back() ,初始条件: 队q 存在且非空,操作结果: 读队尾元素,并返回其值,队不变;
二.2019年普及组第二题:海港调度员
家人们,直接上题目
1.题目描述
小 K 是一个海港的海关工作人员,每天都有许多船只到达海港,船上通常有很多来自不同国家的乘客。
小 K 对这些到达海港的船只非常感兴趣,他按照时间记录下了到达海港的每一艘船只情况;对于第 i 艘到达的船,他记录了这艘船到达的时间 t_i (单位:秒),船上的乘客数 k_i,以及每名乘客的国籍 x_{i,1}, x_{i,2}……x_{i,k}。
小K统计了 n 艘船的信息,希望你帮忙计算出以每一艘船到达时间为止的 24 小时(24 小时 =86400 秒)内所有乘船到达的乘客来自多少个不同的国家。
形式化地讲,你需要计算 n 条信息。对于输出的第 i条信息,你需要统计满足 t_i-86400<t_p ≤ti 的船只 p,在所有的 x_{p,j} 中,总共有多少个不同的数。
2.输入格式
第一行输入一个正整数 n,表示小 K 统计了 n 艘船的信息。
接下来 n 行,每行描述一艘船的信息:前两个整数 t_i 和 k_i分别表示这艘船到达海港的时间和船上的乘客数量,接下来 k_i 个整数 x_{i,j}表示船上乘客的国籍。
保证输入的 t_i 是递增的,单位是秒;表示从小K第一次上班开始计时,这艘船在第 t_i秒到达海港。
3.输出格式
输出 nn 行,第 ii 行输出一个整数表示第 ii 艘船到达后的统计信息。
输入1
3
1 4 4 1 2 2
2 2 2 3
10 1 3
输出1
3
4
4
输入2
4
1 4 1 2 2 3
3 2 2 3
86401 2 3 4
86402 1 5
输出2
3
3
3
4
直接上代码
#include<bits/stdc++.h>
using namespace std;
struct node{//结构体存人的信息
int ti, co;//时间,国家(英文我不会拼……)
};
queue<node> peo;//浅浅的写个队列
int n, new_ti, new_co,na[100005],man,ans;
// 船的数量,来的时间,本船每人国家,国家计数器数组,本船人数,答案。
int main(){
cin>> n;//输入船的数量
for(int i = 1;i<=n;i++){//用船的数量循环
cin>> new_ti>>man;//输入来的时间,本船人数
for(int i = 1;i<=man;i++){//用人的数量循环
cin>> new_co;//输入本船每人国家
if(na[new_co] == 0){//数组na的第new_co个,只有0个人
ans++;//答案计数器自增。
}
na[new_co]++;//数组na的第new_co个,自增。
peo.push({new_ti,new_co});//把时间和城市统统插入peo队列里。
}
while(new_ti - peo.front().ti>=86400&&!peo.empty()){//while循环:如果新插入的人的时间,减去队首人的时间大于等于86400并且peo队列里非空
na[peo.front().co]--;//要删人,数组na的第peo.front().co个(队首人的国家),自减。
if(na[peo.front().co]==0){//如果对手国家已经减到0人了
ans--;//答案自减
}
peo.pop();//弹出队首
}
cout <<ans<<endl;//输出答案(换行)
//现在还在循环里,在for(int i = 1;i<=n;i++)里。
}
return 0;
}
我是用列表做的,还有更多简单的方法,请各位大神多多指点
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%