题目上添加了超链接,大家点一下题目就会自动跳转到Poj原题界面~~              冲鸭冲鸭ヾ(◍°∇°◍)ノ゙。

队列相较于其它数据结构的特点是先进先出,通常也是通过数组、链表实现。

通过数组实现时,为解决伪溢出问题,常需要采用循环队列。做题时用数组实现就足以应对绝大部分题目。

常见题型有模拟、单调队列(挺难的,也是很多进阶优化算法的基础)、以及后续的搜索题....很重要,需要打好基础。

最后一道题2823尤为经典重要。相关课程我看的少,有感觉讲的特别好、特别浅显深刻的,欢迎大家留言分享(好想自己录一个)


3.2.1 Card Trick (3032)

题意:一堆牌有n张,从牌堆顶部开始,第i次将i张牌放到牌底,然后将新的牌顶的牌从牌堆中取走。求取走的n张牌在原牌堆中的位置。

小笔记:简单模拟


#include <cstdio>
#include <queue>
using namespace std;
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
queue<int> Q;
int a[15]; //记录每张牌在原队列中的位置
int k = 1; //记录取牌顺序
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
Q.push(i); //将所有牌入队列
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= i; j++)
{
Q.push(Q.front());
Q.pop();
}
a[Q.front()] = k++;
Q.pop();
}
for (int i = 1; i <= n; i++)
printf("%d ", a[i]);
printf("\n");
}
return 0;
}



3.2.2 Card Stacking (3629)

题意:N个玩家围成一圈打牌,牌堆共有K张牌(K为N的倍数),其中包含M=K/N张好牌和K-M张坏牌。然后和上一题差不多。

小笔记:模拟,发到手里的牌直接出列,其他牌再次入列,发到发牌人手中的牌记录这种牌的最初编号。


#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
int main()
{
queue<int> Q;
int a[50005]; //记录好牌的编号
int n, k, p;
scanf("%d%d%d", &n, &k, &p);
for (int i = 1; i <= k; i++)
Q.push(i);
int m;
for (m = 0; m < k / n; m++)
for (int i = 1; i <= n; i++)
{
if (i == n)
a[m] = Q.front();
Q.pop();
for (int j = 0; j < p; j++)
{
Q.push(Q.front());
Q.pop();
}
}
sort(a, a + m);
for (int i = 0; i < m; i++)
printf("%d\n", a[i]);
return 0;
}



​3.2.3 Printer Queue (3125)​

题意:一个队列包含n个打印作业,每个作业有一个优先级(1~9),从队列头开始,如果该作业的优先级比队列中其他所有作业的优先级高,则打印该作业并出列,否则将该作业放入队列尾;打印作业花费时间为1,其他操作不花费时间。求一个队列中给定作业m,等待到打印完该作业共需要多长时间。

小笔记:模拟,每次取队列头,检查队列中是否有比它优先级高的作业,有的话将该作业放入队列尾,否则时间加1后出队列。处理到指定作业m的时候,如果队列中没有比它优先级高的作业,则时间加1,打印该作业;否则将它移到队尾,继续判断下一个作业。


#include <cstdio>
#include <vector>
using namespace std;
struct job
{
int v; //作业的序号
int p; //作业的优先级
job(int a, int b) : v(a), p(b) {}
};
//检查队列Q中是否有优先级比x高的项,如果有,输出真,否则输出假
bool check(vector<job> Q, int x, unsigned int i)
{
while (i < Q.size())
if (x < Q[i++].p)
return true;
return false;
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
//使用STL中的向量vector 实现队列,利用其push_back操作向队列尾部加入数据
vector<job> Q;
int n, m;
scanf("%d%d", &n, &m);
for (int i = 0, p; i < n; i++)
{
scanf("%d", &p);
Q.push_back(job(i, p));
}
int ans = 1;
for (int k = 0; check(Q, Q[k].p, k) || Q[k].v != m; k++)
{
if (check(Q, Q[k].p, k))
Q.push_back(Q[k]);
else
ans++;
}
printf("%d\n", ans);
}
return 0;
}



​3.2.4 Team Queue (2259)​

题意:共有t组元素进行队列操作。

入列操作:元素进入队列之前先从头检查队列中是否有同组的元素,如果有,直接排到同组元素后面,否则排到队列尾。

出列操作:直接取出队列头的元素。

小笔记:按照题意进行队列模拟,一共有 t 组队列Q[1…t], x 所在的组为T[x],用一个队列TQ记录当前元素所在组的信息。


#include <cstdio>
#include <queue>
using namespace std;
const int N = 1001;
int T[1000000]; //元素与队列号的映射
int main()
{
int t, k = 0;
while (scanf("%d", &t) && t)
{
printf("Scenario #%d\n", ++k);
bool v[N]; //标识是否有同组元素
for (int i = 0; i < t; i++)
{
int n;
scanf("%d", &n);
v[i] = false;
while (n--)
{
int x;
scanf("%d", &x);
T[x] = i;
}
}
queue<int> Q[N]; //存储每个组
queue<int> TQ; //存储组号
char cmd[10];
while (scanf("%s", cmd) && cmd[0] != 'S')
{
if (cmd[0] == 'E')
{
int x;
scanf("%d", &x);
int i = T[x];
if (!v[i])
{
v[i] = true;
TQ.push(i); //将元素x所在组号T[x]放入队列TQ
}
Q[i].push(x); // 将元素x放入队列Q[T[x]]
}
else if (cmd[0] == 'D')
{
int i = TQ.front(); //从TQ队列头找到组号i
printf("%d\n", Q[i].front()); //输出Q[i]队列头元素
Q[i].pop();
if (Q[i].empty())
{
TQ.pop();
v[i] = false;
}
}
}
printf("\n");
}
return 0;
}



​3.2.5 Sliding Window (2823)​

题意:数组a[1…n]有n个数字,依次计算a[1…k]到A[n-k+1…n]区间的最大值和最小值。

小笔记:这道题特别重要,十分精华。一种方法是滑动窗口、单调队列的思想应用,一定要掌握。到后面我们还会学习线段树,也是对这种反复问询区间问题的杀招。


#include <cstdio>
#include <queue>
using namespace std;
int a[1000005];
int main()
{
int n, k;
scanf("%d%d", &n, &k);
//求区间最小值
deque<int> minQ;
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
while (!minQ.empty() && a[i] < a[minQ.back()])
minQ.pop_back();
minQ.push_back(i);
if (minQ.front() < i - k + 1)
minQ.pop_front();
if (i >= k)
printf("%d ", a[minQ.front()]);
}
printf("\n");
//求区间最大值
deque<int> maxQ;
for (int i = 1; i <= n; i++)
{
while (!maxQ.empty() && a[i] > a[maxQ.back()])
maxQ.pop_back();
maxQ.push_back(i);
if (maxQ.front() < i - k + 1)
maxQ.pop_front();
if (i >= k)
printf("%d ", a[maxQ.front()]);
}
printf("\n");
return 0;
}