耗时就900ms算很慢了,有的帖子用int整型存我觉得很好,但是不常用的人会不熟悉用法,所以我还是直接采用的节点+队列模拟,简单粗暴。
基本思路:
其实只要某一次跳转成环了且无匹配,就成了死锁,所以就像消消乐一样,消到最后不能消了就有答案了。
实现:
每个进程命令用一个队列存储,通过send和receive关系每次从第一个不为空的进程处开始跳转,当某次跳转时前后匹配,则前后队列命令出队列,再重新从第一个不为空的进程处开始跳转循环找下去,直到某一次跳转成环且无匹配项(即死锁)或者所有队列为空(匹配成功),退出循环。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
using namespace std;
const int MAX_N = 10000;
struct Node {
int sr, flag;
};
int T, n, tmp;
string op;
queue<Node> num[MAX_N];
void make_queue() {
for(int i = 0; i < n; i++) {
op = "";
getline(cin, op);
//将命令入队
for(int j = 0; j < op.size(); j++) {
if(op[j] == ' ') continue;
else if(op[j] == 'R' || op[j] == 'S') {
tmp = (op[j++] == 'S' ? 1 : -1);
Node node;
node.flag = tmp;
tmp = 0;
while(j < op.size() && op[j] != ' ') {
tmp = tmp * 10 + op[j++] - '0';
}
node.sr = tmp;
num[i].push(node);
}
}
}
}
//配对条件为num[p].front().flag != num[q].front().flag
// && num[q].front().sr == p;
void is_valid() {
//用于记录是否成环
int v[MAX_N] = {0}, is_change = 1, p ,q;
while(is_change) {
//reset
memset(v, 0, sizeof(v));
p = 0;
is_change = 0;
while(p < n && num[p].empty()) p++;
if(p == n) break;
q = num[p].front().sr;
v[p] = 1;
while(!is_change && !v[q] && !num[q].empty()) {
v[q] = 1;
//match
if(num[q].front().sr == p && num[p].front().flag != num[q].front().flag) {
is_change = 1;
num[p].pop();
num[q].pop();
continue;
}
p = q;
q = num[p].front().sr;
}
}
//输出答案顺便清空队列
int ans = 0;
for(int i = 0; i < n; i++) {
if(!num[i].empty()) {
ans = 1;
//清空队列
queue<Node> empty;
swap(empty, num[i]);
}
}
cout << ans << endl;
return ;
}
int main () {
//带\n可以不影响getline的输入
scanf("%d%d\n", &T, &n);
while(T--) {
make_queue();
is_valid();
}
return 0;
}
注意:
可以用getline读取一行,但是在大量数据的情况下会超时,所以用scanf()比较好,本题用scanf可以快100多ms:
char op[10000];
scanf("%[^\n]s", op);
getchar();
后面的getchar()是清除缓冲区的换行符。
但不管哪一种,都要注意在读入一行之前清除缓冲区遗留的换行符。有两种办法:
1、上一个scanf后面带一个\n,就不用清除。
2、上一个scanf后用getchar()