CSP认证2019.03 的第四题

消息传递窗口
最近在刷CSP认证2019年三月份的第四题,主体思路是开n个队列,分别去维护n个进程,之前的想法是直接暴力,去判断这n个队列的队首元素是否匹配,本以为没有问题。但是出现了玄学错误,官网测试上报的是超时。
经后面发现是读入挂了。附上原来的读入程序

cin >> T >> n;
	getchar();
	while (T--) {
        for (int i = 0; i < n; i++) {
            while(!q[i].empty()) q[i].pop();
        }
		int flag = 0, o = 0;
		for (int i = 0; i <= 10005; i++) fill(vis[i],vis[i] + 10,0);
		for (int i = 0; i < n; i++) {
			  do {
					scanf("%c%d",&tmp.ch,&tmp.num);
					q[i].push(tmp);

			  }while (getchar()!='\n')
		}

在本地运行是正确的,不懂挂在哪里。
下面附上改进版的读入程序
思路也改进了,之前暴力会T,后面采用了广搜。
具体思想:初始化:取n个队列的队首元素入广搜队列。
然后取出广搜队列里的队首元素,判断其与其他n个进程队列里的队首元素是否匹配,若匹配,则相应进程的两个队列的队首元素均出队,并且需要打上标记。
(没听懂没关系,下面用例子说明)
注意不管匹配不匹配,广搜队列里的队首元素都会出队列。
例:T = 1,n = 2
S1 R0
R0 S1
初始化:广搜队列里有

S1R0

取出广搜队列里的队首元素:S1,发现与进程1里的R0相匹配,因此将广搜队列里的R0打上标记,下次遍历到它时,直接跳过;并且将S1,R0分别从原来的进程队列里pop出去,此时应将R0和S1入队列。需要注意的是将程序从进程队列里pop出去时,若进程队列非空的话,需要将进程队列新的队首元素重新入广搜队列。
打上标记的做法用一个vis[a][b]//a表示第几个进程,b表示在进程里的位置
S1(vis[0][0]) R0(vis[0][1])
R0(vis[1][0]) S1(vis[1][1])

但是最终只得了90分,不知道哪里出错了。
希望能帮助到大家。


#include <bits/stdc++.h>
using namespace std;
struct data {
	char ch;//字母R/s 
	int num;//R/s后面接的数字 
	int belong;//属于哪个进程 
	int pos;//每个进程对应的位置 
};
queue<data>q[10005];//每个队列维护相应的进程
queue<data>mq; 
int vis[10005][10];
char str[20];
int main()
{
	char str[20];
	int T, n;
	data tmp, tmp1;
	cin >> T >> n;
	getchar();
	while (T--) {
        for (int i = 0; i < n; i++) {
            while(!q[i].empty()) q[i].pop();
        }
		int flag = 0, o = 0;
		for (int i = 0; i <= 10005; i++) fill(vis[i],vis[i] + 10,0);
		for (int i = 0; i < n; i++) {
			int number = 0;
			int ans = 0;
			gets(str);
			for (int j = 0; j < strlen(str); j++) {
				if (str[j] == 'R' || str[j] == 'S') {
					tmp.ch = str[j];
					int p = j + 1;
					while (str[p] >= '0' && str[p] <= '9') {
						number += str[p] - '0';
						ans = number;
						number *= 10;
						p++;
					}
					tmp.belong = i;
					tmp.num = ans;
					tmp.pos = o++;
					ans = 0;
					number = 0;
					q[i].push(tmp);
				}
			}
			
		}
		for (int i = 0; i < n; i++) {
			tmp = q[i].front();
			mq.push(tmp);
		}	
		while (!mq.empty()) {
			tmp = mq.front();
			mq.pop();
			if (vis[tmp.belong][tmp.pos]) continue;
			if (!q[tmp.num].empty())tmp1 = q[tmp.num].front();
			else continue;
			if ((tmp.ch == 'R' && tmp1.ch == 'S' && tmp1.num == tmp.belong) || (tmp.ch == 'S' && tmp1.ch == 'R' && tmp1.num == tmp.belong)) {
				q[tmp.num].pop();
				if (!q[tmp.num].empty()) mq.push(q[tmp.num].front());
				vis[tmp.num][tmp1.pos] = 1;
				q[tmp.belong].pop();
				if (!q[tmp.belong].empty()) mq.push(q[tmp.belong].front());			
			}			
		}	
		for (int i = 0; i < n; i++) {
			if (q[i].empty()) flag++;
		}
		if (flag == n) printf("0\n");//无死锁 
		else printf("1\n");//有死锁				
	}	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值