Round9—循环队列及综合

判断题:

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的数组来实现循环队列,且当前frontrear的值分别为0和4。当从队列中删除两个元素,再加入两个元素后,frontrear的值分别为多少? (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代替一般循环队列中的frontrear指针来表示队列的范围,那么这样的循环队列可以容纳的元素个数最多为: (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 ≤10​5​​),下一行给出从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的算法是一样的。

 

  • 7
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
循环队列可以用来实现舞伴配对问题。我们可以将男女分别存储在两个循环队列中,每次从男队和女队的队头各出一个人配成舞伴,如果两队初始人数不等,则较长的那一队中未配对者等待下一轮舞曲。具体实现步骤如下: 1. 初始化两个循环队列,分别存储男女。 2. 输入舞会轮数,每轮循环队列中出队两个人,分别为男女舞伴。 3. 判断两个队列是否为空,如果为空则输出未配对者姓名。 4. 输出每一轮舞伴配对名单。 代码实现如下: ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXSIZE 100 typedef struct { char name[20]; int gender; // 0表示女性,1表示男性 } Person; typedef struct { Person data[MAXSIZE]; int front, rear; } Queue; void InitQueue(Queue *Q) { Q->front = Q->rear = 0; } int QueueEmpty(Queue Q) { return Q.front == Q.rear; } int QueueFull(Queue Q) { return (Q.rear + 1) % MAXSIZE == Q.front; } void EnQueue(Queue *Q, Person x) { if (QueueFull(*Q)) { printf("Queue is full!\n"); exit(1); } Q->data[Q->rear] = x; Q->rear = (Q->rear + 1) % MAXSIZE;} Person DeQueue(Queue *Q) { if (QueueEmpty(*Q)) { printf("Queue is empty!\n"); exit(1); } Person x = Q->data[Q->front]; Q->front = (Q->front + 1) % MAXSIZE; return x; } void Match(Queue *male, Queue *female, int rounds) { int i; for (i = 1; i <= rounds; i++) { printf("Round %d:\n", i); if (QueueEmpty(*male) || QueueEmpty(*female)) { printf("No enough people!\n"); break; } Person m = DeQueue(male); Person f = DeQueue(female); printf("%s and %s are matched!\n", m.name, f.name); if (male->rear > male->front) { EnQueue(male, m); } if (female->rear > female->front) { EnQueue(female, f); } } if (!QueueEmpty(*male)) { printf("The following males are not matched:\n"); while (!QueueEmpty(*male)) { Person m = DeQueue(male); printf("%s\n", m.name); } } if (!QueueEmpty(*female)) { printf("The following females are not matched:\n"); while (!QueueEmpty(*female)) { Person f = DeQueue(female); printf("%s\n", f.name); } } } int main() { Queue male, female; InitQueue(&male); InitQueue(&female); // 初始化男女队列 Person m1 = {"Tom", 1}; Person m2 = {"Jack", 1}; Person m3 = {"Mike", 1}; EnQueue(&male, m1); EnQueue(&male, m2); EnQueue(&male, m3); Person f1 = {"Lucy", 0}; Person f2 = {"Lily", 0}; Person f3 = {"Mary", 0}; EnQueue(&female, f1); EnQueue(&female, f2); EnQueue(&female, f3); Match(&male, &female, 3); return 0; } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值