并行程序模拟 Concurrency Simulator
题目描述
你的任务是模拟 n n n个程序(按输入顺序编号 1 1 1~ n n n)的并行执行。每个程序包含不超过25条语句。
格式一共是5种:赋值( v a r = c o n s t a n t var=constant var=constant),打印(print v a r var var), l o c k lock lock, u n l o c k unlock unlock, e n d end end,耗时分别为 t 1 , t 2 , t 3 , t 4 , t 5 t_1,t_2,t_3,t_4,t_5 t1,t2,t3,t4,t5。
变量用一个小写字母表示,初始时为 0 0 0,为所有并行程序共有,且它的值始终保持在 [ 0 , 100 ] [0,100] [0,100] 内,所以一个程序对某一个变量的赋值会影响到另外一个程序。
每个时刻只能是一个程序处于运行状态,其他程序处于等待状态。运行状态之中的的程序每次最多分配 Q Q Q 个单位时间,一旦在未执行完程序时超过分配时间,这个程序则会被插入等待队列,然后从其的队首取出一共程序继续执行。而初始的等待队列为按照输入程序排入。
但是由于 l o c k lock lock 和 u n l o c k unlock unlock 命令的出现,这个顺序会被改变。
l o c k lock lock 的作用是申请对所有变量的独占访问, u n l o c k unlock unlock 则是解除对所有变量的独占访问,且它们一定成对出现。当一个程序已经对所有的变量独占访问后,其他程序若试图执行 l o c k lock lock,无论其是否耗尽分配时间,都会被放在一个阻止队列的尾部,且当那个程序解除的时候,则会从阻止队列的头部的程序进入等待队列的头部。
现在给出 n , t 1 , t 2 , t 3 , t 4 , t 5 , Q n,t_1,t_2,t_3,t_4,t_5,Q n,t1,t2,t3,t4,t5,Q 以及 n n n 个程序,你需要输出所有 p r i n t print print 命令执行输出的值。
输入格式
第一行数据组数
第二行空行
第三行分别是n t1 t2 t3 t4 t5 Q用空格隔开
下面是n段程序,每组数据的程序用空行隔开
样例 #1
样例输入 #1
1
3 1 1 1 1 1 1
a = 4
print a
lock
b = 9
print b
unlock
print b
end
a = 3
print a
lock
b = 8
print b
unlock
print b
end
b = 5
a = 17
print a
print b
lock
b = 21
print b
unlock
print b
end
样例输出 #1
1: 3
2: 3
3: 17
3: 9
1: 9
1: 9
2: 8
2: 8
3: 21
3: 21
分析
题目是洛谷翻译的,它原本的样例输入和输出有一点问题,原题来源于UVA OJ平台.
题目关键信息已加粗,还有一点是,当时间配额不够用时,当存在语句时要把该语句执行完再加入等待队列.简单来说,就是剩余的时间>0但是小于执行该语句所需要的时间,那也要把该语句执行完.
思维难度不大,是一道模拟类的题目,这里用双端队列来模拟等待队列(就绪队列),使用普通队列来模拟阻止队列.
#include <deque>
#include <queue>
#include <string>
#include <map>
#include <iostream>
using namespace std;
typedef struct Program{
int id;
int point;
string statements[30];
Program(int id, int point):id(id), point(point){}
} Program;
void algo();
int n = 0;
int t1, t2, t3, t4, t5;
int Q = 0;
int main(int argc, char **argv)
{
int times = 0;
cin >> times;
for(int i = 0; i < times; i++){
cin >> n >> t1 >> t2 >> t3 >> t4 >> t5 >> Q;
getchar();
algo();
if(i != times-1){
cout << endl;
}
}
return 0;
}
void algo(){
deque<Program> wait;
queue<Program> stop;
map<char, string> vars;
string end = "end";
for(int i = 0; i < n; i++){
Program program(i, 0);
string statement;
int count = 0;
while(end.compare(statement) != 0){
getline(cin, statement);
program.statements[count++] = statement;
}
wait.push_back(program);
}
int lock = 0;
while(!wait.empty()){
Program p = wait.front();
wait.pop_front();
bool finished = false;
bool stopped = false;
int t = Q;
while(t > 0){
string s = p.statements[p.point];
p.point++;
if(s.compare("lock") == 0){
if(lock == 1){
stopped = true;
p.point--;
stop.push(p);
break;
}else{
lock = 1;
t -= t3;
}
}else if(s.compare("unlock") == 0){
if(!stop.empty()){
Program sp = stop.front();
stop.pop();
wait.push_front(sp);
}
t -= t4;
lock = 0;
}else if(s.substr(0, 5).compare("print") == 0){
t -= t2;
cout << p.id+1 << ": " << (vars[s[6]].compare("") == 0 ? "0" : vars[s[6]]) << endl;
}else if(s.compare("end") == 0){
finished = true;
t -= t5;
break;
}else{
vars[s[0]] = s.substr(4);
t -= t1;
}
}
if(!stopped && !finished){
wait.push_back(p);
}
}
}
刚开始做的时候,按照洛谷的输入和输出格式,一直没有AC,翻了一下原网站才知道,给我整无语了:)
总来说,主要锻炼一下C++的STL库的运用,主要用到的数据结构是队列,另外也是用map来进行存储变量的值.
这里说到map当时也遇到一个问题,当时我的value设置的是string类型的,当我们使用下标语法访问map中的键值时,如果key不存在,则map会执行一个插值函数(insert),这个插入的默认值依据数据类型来确定,如果是内置的基本数据类型,那就是0,如果是string则为空串,当为我们自定义的类型时,默认值为我们内部默认提供的初始值.