借鉴大神的代码↓
https://www.cnblogs.com/xidian-mao/p/10568594.html
借鉴大神的代码↑
思路分析
每组作业都有n个进程发出不同的指令,大体上来看,需要消去成对出现的接收和发送指令(每个进程最多有8个指令),因此需要将每组进程消息整理为发送和接收序列,记录消去的对数,若恰好全部消去,则不会死锁,否则会发生死锁
怎么整理呢?
为了将抽象变具体,首先构造消息结构,将每组作业的进程指令转换为消息,每个进程的消息并行入队,出队一个消息,并查找接收/发送序列中对应的结果,若没有相应结果,记录到接收/发送序列中,消去的对数减一;若有相应的结果,接收/发送序列中的结果置为-1,消去的对数加一,重复这个过程,知道所有消息都出队,检查消去的对数,如果对数为0,则全部消去,不会发生死锁,否则会发生死锁
#include <bits/stdc++.h>
using namespace std;
// 最大进程数
const int N = 1e4 + 7;
// 某个进程的消息数量
int num[N];
// 消息结构体
struct message {
int x, y; // x, 当前进程; y, 目标进程
bool flag; // true为 发送, false为 接收
};
// 一个作业的消息序列
message msg[N][9];
// 消息队列
queue <message> q;
// 发送序列 接收序列
int s[N], r[N];
// 字符串容器
typedef vector <string> vstr;
// 字符串分隔
vstr split(string str, char flag = ' ') {
vstr res;
istringstream iss(str);
while (getline(iss, str, flag)) {
if (str.size()) {
res.push_back(str);
}
}
return res;
}
// 字符转数字
int to_int(string str) {
int res = 0;
for (int size = str.size(), i = size - 1; i >= 0; --i) {
res += pow(10, size - i - 1) * (str[i] - '0');
}
return res;
}
// 所有进程的第一个消息入队
void enqueue(int k) {
if (num[k] > 0) {
q.push(msg[k][num[k]]);
num[k]--;
}
}
int main() {
int T, n, i = 0, j = 0;
bool complete = false;// 一对指令通信完成的标志
cin >> T;
cin >> n;
cin.ignore();// 清除一个字符(通常为换行符)
string line;
while (T--) {
// 每个作业开始前,一定要初始化,r与s两个序列一定初始化为-1,否则后面查询是否消去的时候在进程0的时候会误判
memset(s, -1, sizeof(s));
memset(r, -1, sizeof(r));
memset(msg, 0, sizeof(msg));
memset(num, 0, sizeof(num));
for (int i = 0; i < n; ++i) {
getline(cin, line);
vstr vs = split(line);
num[i] = vs.size();// 记录进程的消息数量
// 将一组字符串转为消息,倒序存储,配合enqueue函数
for (int j = 0, size = vs.size(); j < size; ++j) {
int k = size - j;
msg[i][k].x = i;
msg[i][k].y = to_int(vs[j].substr(1));
if (vs[j][0] == 'S') {
msg[i][k].flag = true;
}
else {
msg[i][k].flag = false;
}
}
}
for (int i = 0; i < n; ++i) {
// 所有进程的第一个消息入队
enqueue(i);
}
int sum = 0;
while (!q.empty()) {
message _msg = q.front();
q.pop();
bool complete = false;
int x = _msg.x, y = _msg.y;
// 如果 当前进程 发送给 目标进程消息
if (_msg.flag) {
if (r[y] == x) {
complete = true;
// 消去对应指令,置为-1
r[y] = -1;
// 两进程的下一消息入队
enqueue(x);
enqueue(y);
}
else {
// 不能消去, 记录下来
s[x] = y;
}
}
else {
// 如果 当前进程 接收 目标进程消息
if (s[y] == x) {
complete = true;
// 消去对应指令,置为-1
s[y] = -1;
// 两进程的下一消息入队
enqueue(x);
enqueue(y);
}
else {
r[x] = y;
}
}
if (complete) {
sum++;
}
else {
sum--;
}
}
if (sum == 0) {
cout << 0 << endl;
}
else {
cout << 1 << endl;
}
}
return 0;
}
学到的新东西1: 不必为引入哪个库而烦恼了!
学到了dev c++一个万能函数头 #include <bits/stdc++.h>
学到的新东西2: c++的流处理 istringstream
可以将一个字符串作为输入流处理,可以愉快地用getline函数,剔除字符串中的空格了!
想到了前面的一篇A+B and C中的scanf来跳过空格且判断改行是否结束,完全可以先拿出一个字符串然后用这种输入流处理!
学到的新东西3:
memset函数,在初始化时这个函数很好用!
小坑1:cin的缓冲区
在执行 cin >> n后,使用string中的获取一行 getline(cin, line),由于cin中有上一行的换行符,会直接把换行符当作一行,所以需要先清理下cin的缓冲区
小坑2:倒序存储每个进程的指令消息
因为需要判断这个进程剩余的进程数量,决定是否需要将该进程的下条消息入队,在初时化进程的指令消息时,倒序存储,且从下标8(最大值)开始,入队函数直接将当前进程剩余数量作为当前进程的第一条消息的索引即可,同时作业的消息序列要申请9个元素空间,而不是8个