📜  门| GATE CS 2021 |设置 1 |第 38 题(1)

📅  最后修改于: 2023-12-03 15:28:38.870000             🧑  作者: Mango

门 | GATE CS 2021 |设置 1 |第 38 题

本题为2021年计算机科学门(GATE CS)考试中的一道题目,是一道数据结构与算法相关的问题。该题目有一定难度,需要有一定算法基础和思维能力。

题目描述

假设有 $N$ 个进程需要占用一个公共资源,资源同时只能被一个进程占用。如果有多个进程同时请求资源,则他们按照序号依次排队执行,即第一个进程先执行,直到占用资源的进程退出后,紧接着执行下一个进程。现在有 $M$ 次请求资源的操作,对于每次请求,给定该进程的序号 $i$,请求类型(请求或者释放)和时间戳 $t$,请编写代码实现上述机制。

输入格式

第一行包含两个正整数 $N$ 和 $M$,分别表示进程数量和操作次数。

接下来 $M$ 行,每行包含三个整数 $i$,$t$ 和 $op$,分别表示第 $i$ 个进程在时间 $t$ 进行请求或者释放操作(0 表示释放,1 表示请求)。

输出格式

输出共 $M$ 行,每行表示对应操作的返回值,如果该操作能立即执行,则输出 1 表示执行成功,否则输出 0。

输入样例
3 7
0 0 1
1 1 1
2 2 1
1 3 0
0 4 0
2 5 0
1 6 1
输出样例
1
1
0
1
1
1
0
题解思路

本题是一道典型的操作系统中进程调度的问题,需要从多个方面考虑进程如何请求和释放公共资源,并且需要按照顺序依次执行请求,直到资源被释放。一般考虑使用队列来实现进程的调度,对于每次请求,如果资源当前被占用,则将该请求加入进程等待队列中,等待资源释放后再依次执行,否则直接执行该请求。对于每次释放操作,则判断等待队列中是否有等待的进程,如果有则依次从队列中弹出加入运行队列中。

根据上述思路,可以设计一个 Process 类来表示每个进程,包括进程的编号、当前请求是否为占用资源,以及进入等待队列的时间戳。同时可以设计一个 std::deque 类型的等待队列等待资源的释放,以及一个运行队列保存正在占用资源的进程。每次请求资源时,如果资源空闲,则直接占用,否则将该请求加入当前进程的等待队列中。对于进程释放操作,则将等待队列中的第一个进程弹出,加入运行队列中,并将当前占用资源的进程释放。需要注意的是,如果等待队列中的第一个进程请求占用资源的时间戳与当前进程占用资源释放时间戳相同,则需要先弹出等待队列中的进程,再释放当前进程。

代码实现
#include <iostream>
#include <deque>
using namespace std;

class Process {
public:
    int pid, ts;
    bool acquire;

    Process(int pid, int ts, bool acquire) {
        this->pid = pid;
        this->ts = ts;
        this->acquire = acquire;
    }

    bool operator<(const Process& p) const {
        return ts > p.ts;   // 时间戳越小,优先级越高
    }
};

int main() {
    int n, m;
    cin >> n >> m;

    deque<Process> wait, run;
    int cur_ts = 0, cur_pid = -1;
    for (int i = 0; i < m; i++) {
        int pid, ts, op;
        cin >> pid >> ts >> op;

        while (!wait.empty() && wait.front().ts == cur_ts) {  // 检查等待队列中是否有进程可以运行
            if (cur_pid == -1) cur_pid = wait.front().pid;  // 如果资源空闲,立即运行等待队列中的第一个进程
            run.push_back(wait.front());
            wait.pop_front();
        }

        if (op == 1) {  // 请求资源
            if (cur_pid == -1) {  // 如果资源空闲,则立即占用资源
                cur_pid = pid;
                run.push_back(Process(pid, ts, true));
                cout << 1 << endl;
            } else {  // 否则将请求加入等待队列中
                wait.push_back(Process(pid, ts, true));
                cout << 0 << endl;
            }
        } else {  // 释放资源
            if (pid == cur_pid) {  // 如果是当前进程占用的资源,直接释放
                cur_pid = -1;
                run.pop_front();
                cout << 1 << endl;
            } else {  // 否则在等待队列中查找对应进程,并将其从队列中删除
                bool found = false;
                for (int i = 0; i < wait.size(); i++) {
                    if (wait[i].pid == pid && wait[i].acquire) {
                        found = true;
                        wait.erase(wait.begin() + i);
                        break;
                    }
                }
                if (found) cout << 1 << endl;
                else cout << 0 << endl;  // 如未找到,则说明该请求无效
            }
        }
    }

    return 0;
}