题目来源于 https://blog.csdn.net/wingrez/article/details/88676539
消息传递接口(MPI)是一个并行计算的应用程序接口,常用于超级计算机、计算机集群等环境下的程序设计。
老师给了 T 份 MPI 的样例代码,每份代码都实现了 n 个进程通信。这些进程标号从 0 到 n − 1,每个进程会顺序执行自己的收发指令,如:“S x”,“R x”。“S x”表示向x 号进程发送数据,“R x”表示从 x 号进程接收数据。每一对收发命令必须匹配执行才能生效,否则会“死锁”。
举个例子,x 号进程先执行发送命令“S y”,y 号进程必. 须. 执行接送命令“R x”,这一对命令才执行成功。否则 x 号进程会一直等待 y 号进程执行对应的接收命令。反之,若 y 号进程先执行接收命令“R x”,则会一直等待 x 号进程执行发送命令“S y”,若 x号进程一直未执行发送命令“S y”,则 y 号进程会一直等待 x 号进程执行对应的发送命令。上述这样发送接收命令不匹配的情况都会造成整个程序出现“死锁”。另外,x
号进程不会执行“S x”或“R x”,即不会从自己的进程收发消息。.现在老师请你判断每份样例代码是否会出现“死锁”的情况。每个进程的指令最少有 1 条,最多有 8 条,这些指令按顺序执行,即第一条执行完毕,才能执行第二条,依次到最后一条。
从标准输入读入数据。
输入第一行两个正整数 T, n,表示有 T 份样例代码,实现了 n 个进程通信。
接下来有 T × n 行,每行有若干个(1 − 8 个)字符串,相邻之间有一个空格隔开,表示相应进程的收发指令。不存在非法指令。对于第 2 + i, 0 ≤ i ≤ (T × n − 1) 行,表示第 i ÷ n(商)份代码的 i KQ/ n(余数)号进程的收发指令。
(比如,“S1”表示向 1 号进程发送消息,“R1”表示从 1 号进程接收消息。细节请参考样例。)
输出到标准输出。
输出共 T 行,每行一个数字,表示对应样例代码是否出现“死锁”的情况。1 表示死锁,0 表示不死锁。
3 2
R1 S1
S0 R0
R1 S1
R0 S0
R1 R1 R1 R1 S1 S1 S1 S1
S0 S0 S0 S0 R0 R0 R0 R0
0
1
0
第 1 份代码中,(1)0 号进程执行的“R1”和 1 号进程执行的“S0”成功执行;(2)0 号进程执行的“S1”和 1 号进程执行的“R0”成功执行,所以未发生“死锁”,程序顺利运行。
第 2 份代码中,(1)0 号进程执行的“R1”和 1 号进程执行的“R0”一直在等待发送命令,进入“死锁”状态。
(原题中此处有错误,已更正)
2 3
R1 S1
R2 S0 R0 S2
S1 R1
R1
R2 S0 R0
S1 R1
0
1
第 1 份代码中,(1)2 号进程执行的“S1”和 1 号进程执行的“R2”成功执行;(2)0 号进程执行的“R1”和 1 号进程执行的“S0”成功执行;(3)0 号进程执行的“S1”和 1 号进程执行的“R0”成功执行;(4)1 号进程执行的“S2”和 2 号进程执行的“R1”成功执行;所以未发生“死锁”,程序顺利运行。
第 2 份代码中,(1)2 号进程执行的“S1”和 1 号进程执行的“R2”成功执行;(2)
0 号进程执行的“R1”和 1 号进程执行的“S0”成功执行;(3)1 号进程执行的“R0”
和 2 号进程执行的“R1”一直在等待发送命令;进入“死锁”状态。
耶!第一次独立做出来第四题,不过可能也是因为这道题比较简单吧 (*^▽^*)
思路:刚开始看到这道题我的第一反应是拓扑排序,就感觉很像,但是又感觉不太对劲,去找了一圈果然没有用拓扑排序做的,然后我最后用的是暴力模拟的方法。
- 进行一个大循环,每次循环都遍历n个进程的列表首元素,只有当所有进程的命令列表都为空(sumarr(isempty,n)==0),或者在本次循环中各进程列表都没有改变时才跳出循环(程序中的flag)。
- 如果遍历到的进程k为Sk或Rk,说明在从自己的进程收发消息。这种情况直接让该命令出队,flag=1
- 如果遍历到进程k首元素是Sx,则接下来要看看进程x的首元素是否为Rk。如果是的话,这两个命令就可以抵消,两个进程队列一起出队,并置flag=1;如果进程x的首元素不是Rk,不做任何改变。
- 到最后判断sumarr(isempty,n)==0?,如果=0,说明所有命令都被执行了,未产生死锁,输出1,否则输出0
queue<com> command[MAXN],用一个数组n个进程每个进程都有一个执行的先后顺序,先进先出,所以用queue。用队列数组来存储n个进程的待执行命令列表
isempty[MAXN] 来记录第i个进程的执行命令是否为空,不空isempty[i]=1,空为0。这个数组存在的意义是因为我
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
struct com {
char c;
int num;
com(char c,int num):c(c),num(num) {}
// bool operator ==(com x)const{
// return c==x.c&&num==x.num;
// }
};
const int MAXN=10005;
queue<com> command[MAXN];
int isempty[MAXN]; //判断该列表是否为空,不空为1,空为0
int str2int(string s) {
int res=0;
for(int i=0; i<s.length(); i++) {
res=res*10+s[i]-'0';
}
return res;
}
int sumarr(int a[],int n) { //求a数组的和,来判断是否所有队列全为空,即所有命令都被执行完了
int res=0;
for(int i=0; i<n; i++) {
res+=a[i];
}
return res;
}
int main() {
int t,n;
scanf("%d%d",&t,&n);
string s1,s2;
getchar();
for(int i=0; i<t; i++) {
memset(isempty,0,sizeof(isempty));
for(int j=0; j<n; j++) {
getline(cin,s1);
int index;
while((index=s1.find(' '))!=string::npos) {
s2=s1.substr(0,index);
s1=s1.substr(index+1);
command[j].push(com(s2[0],str2int(string(s2,1))));
// cout<<s2[0]<<" "<<str2int(string(s2,1))<<endl;
isempty[j]=1; //不空
}
command[j].push(com(s1[0],str2int(string(s1,1))));
// cout<<s1[0]<<" "<<str2int(string(s1,1))<<endl;
}
while(sumarr(isempty,n)!=0) {
int flag=0; //如果一轮以后flag仍为0,说明这一轮没有改变
for(int k=0; k<n; k++) {
if(command[k].empty()) {
isempty[k]=0;
continue;
}
com temp1=com('S',0),temp2('S',0); //这个初始化随意的,没有实际意义
temp1=command[k].front();
int from,to; //from的Sto与to的Rfrom相对应
from=k;
to=temp1.num;
if(from==to) { //不会从自己的进程收发消息
flag=1;
command[from].pop();
continue;
}
// cout<<s1<<endl;
if(temp1.c=='S') { //Sx
// temp2=com('R',k); //Rx
if(command[to].empty()) isempty[to]=0; //为空,无法取顶,这种情况下也不能匹配
else if(command[to].front().c=='R' && command[to].front().num==from) { //Sto和Rfrom可以匹配
flag=1;
command[from].pop();
command[to].pop();
}
}
}
if(flag==0) break;
}
if(sumarr(isempty,n)==0) { //0 不死锁
printf("0\n");
} else {
printf("1\n");
}
for(int k=0; k<n; k++) {
while(!command[k].empty()) {
command[k].pop();
}
}
}
return 0;
}