2019-03-04:消息传递接口【100】

题目来源于 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 表示不死锁。

输入样例1

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

输出样例1

0
1
0

样例解释1

第 1 份代码中,(1)0 号进程执行的“R1”和 1 号进程执行的“S0”成功执行;(2)0 号进程执行的“S1”和 1 号进程执行的“R0”成功执行,所以未发生“死锁”,程序顺利运行。
第 2 份代码中,(1)0 号进程执行的“R1”和 1 号进程执行的“R0”一直在等待发送命令,进入“死锁”状态。
(原题中此处有错误,已更正)

输入样例2

2 3
R1 S1
R2 S0 R0 S2
S1 R1
R1
R2 S0 R0
S1 R1

输出样例2

0
1

样例解释2

第 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;
}

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值