紫书刷题进行中,题解系列【GitHub|CSDN】
例题6-1 UVA210 Concurrency Simulator(64行AC代码)
题目大意
题目难懂,仔细读题
给定若干个程序,每个程序包含若干条指令,给出每个命令执行所需时间和每个程序的可用时间,模拟指令执行输出相应信息。
五条指令如下:
variable = constant
:赋值语句,变量variable
为单字符(26个小写字母,全局共享),初值为0,常量constant
为小于100的整数print variable
:打印变量值lock
:上锁,独占变量资源unlock
:解锁,接触独占变量资源end
:程序结束
模拟过程中存在两个队列:
- ready:准备队列,依次执行该队列的程序
- block:阻塞队列,当已有程序进入lock,其它程序再次遇到lock指令时,需将该程序插入block末尾;当有程序执行unlock后,将block队首加入ready队首
注意1:当目前指令执行所需时间大于剩余可用时间时,也要完整执行
思路分析
主要是队列和双端队列模拟,因此定义如下数据结构,队列q1表示每个程序对应的指令,双端队列qr表示ready队列,存储各个程序的编号;qb为阻塞队列,存储被阻塞的程序编号
queue<string> q1[a[0]]; deque<int> qr; queue<int> qb; // 每个程序对应指令;ready;阻塞
为了处理全局变量,定义map<string, string> vmp;
表示变量对应的值,注意给26个小写字母初始化为0
其余只需按照每个命令对应的操作处理即可,仅涉及队列的插入和删除,详见代码注释
注意点
- 初始化26个字母对应的值为0
- 访问和出队时注意先判断队列是否为空
- 测试样例漏了第一行的测试用例个数
- 当目前指令执行所需时间大于剩余可用时间时,也要完整执行
- 当遇到阻塞,lock这条指令不算被执行,依旧保留在源程序,一块加入阻塞队列
AC代码(C++11,双端队列,字符串处理)
#include<bits/stdc++.h>
using namespace std;
int T, a[7]; // 测试用例个数,a[0-6]分别表示输入的7个数
string s, ans;
int main() {
cin >>T;
for (int i = 0; i < T; i ++) {
for (int j = 0; j < 7; j ++) scanf("%d", &a[j]);
getchar(); // 吸收多余字符
queue<string> q1[a[0]]; deque<int> qr; queue<int> qb; // 每个程序对应指令;ready;阻塞
for (int j = 0; j < a[0]; j ++) { // n个程序
while (getline(cin, s) && s != "end") q1[j].push(s);
qr.push_back(j);
}
if (i != 0) puts(""); // 连续输出的空行
map<string, string> vmp; // 变量对应的值
bool isLock = false; // 标记是否有锁
while (!qr.empty()) { // 等待队列非空
int t = 0, k = qr.front(); qr.pop_front(); // 耗费时间,当前程序编号
bool isBlock = false; // 标记是否发生阻塞
while (t < a[6] && !q1[k].empty()) { // 未超时
s = q1[k].front(); // 取出第一条命令
int j = s.find('=');
if (j != string::npos) { // 赋值
vmp[s.substr(0,j-1)] = s.substr(j+2);
t += a[1]; // 计时
}
else {
j = s.find(' ');
if (j != string::npos) { // 打印输出
ans = "0"; // 初始化
if (vmp[s.substr(j+1)] != "") ans = vmp[s.substr(j+1)];
printf("%d: %s\n", k+1, ans.c_str()); // print val
t += a[2];
}
else {
if (s[0] == 'l') { // lock
if (!isLock) { // 未有锁定
isLock = true;
t += a[3]; // 时间增加
}
else { // 已有锁定
qb.push(k); // 加入阻塞队列尾部
isBlock = true;
break; // 直接退出,忽略其它剩余时间
}
}
else if (s[0] == 'u') { // unlock
isLock = false; // 标记未锁定
if (!qb.empty()) { // 阻塞非空
qr.push_front(qb.front()); // 阻塞头部加入ready头部
qb.pop();
}
t += a[4];
}
}
}
q1[k].pop(); // 确保阻塞时lock命令不会被删除
}
if (!q1[k].empty() && !isBlock) qr.push_back(k); // 非空再次加入等待队列尾部
}
}
return 0;
}