判断题:
1-1所谓“循环队列”是指用单向循环链表或者循环数组表示的队列。(F) (1分)
解析:循环队列是一个抽象的数据结构,而单向循环链表和循环数组都是具体的实现方法并不是数据结构的本身。
1-2在用数组表示的循环队列中,front值一定小于等于rear值。(F) (1分)
解析:由于出队与入队操作front = (front+1)% n,rear = (rear + 1)% n;
我们只能保证front与rear是在0到n-1之间的,但是我们无法保证front是一直小于等于rear的。
1-3不论是入队列操作还是入栈操作,在顺序存储结构上都需要考虑"溢出"情况。(T) (2分)
解析:题目当中说明了,在顺序结构上考虑,由于顺序结构我们使用数组实现的。因此,我们需要考虑数组的长度,但是如果我们是用链表这样的链式存储结构,就不需要考虑了。
选择题:
2-1若用大小为6的数组来实现循环队列,且当前front
和rear
的值分别为0和4。当从队列中删除两个元素,再加入两个元素后,front
和rear
的值分别为多少? (2分)
- 2和0
- 2和2
- 2和4
- 2和6
解析:删除元素永远都是front指针移动,也就是永远都是队列的首元素出队列,插入元素永远都是rear指针移动,也就是说元素入队都是插入在队尾。
那么我们可以根据front = (front+1)% n,rear = (rear + 1)% n来计算操作之后的front与rear的值是多少。
2-2如果循环队列用大小为m
的数组表示,且用队头指针front
和队列元素个数size
代替一般循环队列中的front
和rear
指针来表示队列的范围,那么这样的循环队列可以容纳的元素个数最多为: (2分)
m-1
m
m+1
- 不能确定
解析:我们前面采用front与rear指针来实现循环队列其中队满的判断是front = (rear+ 1)% n来判断的,因此我们是实际容纳元素的个数就是m-1,但是这里我们用size代替了rear指针,也就是说我们队满可以用size与m的关系来判断。
因此这里的实际容纳元素的数目就是m。
2-3如果循环队列用大小为m
的数组表示,队头位置为front
、队列元素个数为size
,那么队尾元素位置rear
为: (2分)
front+size
front+size-1
(front+size)%m
(front+size-1)%m
解析:在这里我们要看清楚rear指针到底是指向的哪里,在这里rear指向的是最后一个元素的位置,并不是最后一个元素的后面,也就是这里的rear指针指向的不是插入位置。
因此rear = (front + size - 1)% m。
编程题:
7-1 银行排队问题之单队列多窗口服务 (25 分)
假设银行有K个窗口提供服务,窗口前设一条黄线,所有顾客按到达时间在黄线后排成一条长龙。当有窗口空闲时,下一位顾客即去该窗口处理事务。当有多个窗口可选择时,假设顾客总是选择编号最小的窗口。
本题要求输出前来等待服务的N位顾客的平均等待时间、最长等待时间、最后完成时间,并且统计每个窗口服务了多少名顾客。
输入格式:
输入第1行给出正整数N(≤1000),为顾客总人数;随后N行,每行给出一位顾客的到达时间T
和事务处理时间P
,并且假设输入数据已经按到达时间先后排好了顺序;最后一行给出正整数K(≤10),为开设的营业窗口数。这里假设每位顾客事务被处理的最长时间为60分钟。
输出格式:
在第一行中输出平均等待时间(输出到小数点后1位)、最长等待时间、最后完成时间,之间用1个空格分隔,行末不能有多余空格。
在第二行中按编号递增顺序输出每个窗口服务了多少名顾客,数字之间用1个空格分隔,行末不能有多余空格。
输入样例:
9
0 20
1 15
1 61
2 10
10 5
10 3
30 18
31 25
31 2
3
输出样例:
6.2 17 61
5 3 1
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000;
struct Person
{
int arrive_time;
int use_time;
int wait_time;
int end_time;
bool vis;
Person(int arrive_time, int use_time) : arrive_time(arrive_time), use_time(use_time)
{
wait_time = 0;
vis = false;
}
};
struct Window
{
int nums;
int end_time;
Window() : nums(0) {}
};
bool vis_time[15][maxn * 6];
int n, k, max_wait, all_time;
vector<Person> G;
vector<Window> P;
void solve()
{
queue<Person> que;
for(int now_time = 0; ; now_time++)
{
if(que.size() >= n)
return ;
for(int i = 0; i < k; i++)
{
if(vis_time[i][now_time])
continue;
for(int j = 0; j < n; j++)
{
if(G[j].vis)
continue;
if(G[j].arrive_time <= now_time)
{
P[i].nums++;
G[j].wait_time = now_time - G[j].arrive_time;
max_wait = max(max_wait, G[j].wait_time);
G[j].end_time = now_time + G[j].use_time;
G[j].vis = true;
for(int time = 0; time < G[j].use_time; time++)
vis_time[i][now_time + time] = true;
que.push(G[j]);
break;
}
else
break;
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin >> n;
for(int i = 0; i < n; i++)
{
int arrive_time, use_time;
cin >> arrive_time >> use_time;
if(use_time > 60)
use_time = 60;
G.push_back(Person(arrive_time, use_time));
}
cin >> k;
for(int i = 0; i < k; i++)
P.push_back(Window());
solve();
double time = 0;
for(int i = 0; i < n; all_time = max(all_time, G[i].end_time), i++)
time += G[i].wait_time;
cout << fixed << setprecision(1) << time / n << " ";
cout << max_wait << " " << all_time << endl;
cout << P[0].nums;
for(int i = 1; i < k; i++)
cout << " " << P[i].nums;
cout << endl;
return 0;
}
解析:其实也不是队列,就是大模拟。
7-2 列车调度 (25 分)
火车站的列车调度铁轨的结构如下图所示。
两端分别是一条入口(Entrance)轨道和一条出口(Exit)轨道,它们之间有N
条平行的轨道。每趟列车从入口可以选择任意一条轨道进入,最后从出口离开。在图中有9趟列车,在入口处按照{8,4,2,5,3,9,1,6,7}的顺序排队等待进入。如果要求它们必须按序号递减的顺序从出口离开,则至少需要多少条平行铁轨用于调度?
输入格式:
输入第一行给出一个整数N
(2 ≤ N
≤105),下一行给出从1到N
的整数序号的一个重排列。数字间以空格分隔。
输出格式:
在一行中输出可以将输入的列车按序号递减的顺序调离所需要的最少的铁轨条数。
输入样例:
9
8 4 2 5 3 9 1 6 7
输出样例:
4
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 5;
int a[maxn];
int dp[maxn];
bool vis[maxn];
int n;
int main()
{
cin >> n;
for(int i = 0; i < n; i++)
cin >> a[i];
int cnt = 1;
dp[0] = a[0];
for(int i = 1; i < n; i++)
{
if(a[i] > dp[cnt - 1])
{
dp[cnt++] = a[i];
vis[i] = true;
}
else
{
int pos = lower_bound(dp, dp + cnt, a[i]) - dp;
dp[pos] = a[i];
}
}
cout << cnt << endl;
return 0;
}
解析:我们根据贪心的策略,能够分析出实际上的操作跟求LIS的nlogn的算法是一样的。