csp201903-4
一、getline()数的总结
getline()函数是一个比较常见的函数,用这个函数完成读入一行数据
在C++中getline()函数的有两种,一种是在头文件中,是食istream类的成员函数,另一种在头文件中,是普通函数
第一种:在中的getline()函数有两种重载形式:
istream&getline(char* s,streamsize n);
istream&getline(char* s,streamsize n,char delim);
作用是:从istream中读取至多n个字符(包含结束标记符)保存在s对应的数组中,即使还没读够n个字符
如果遇到delim或字数达到限制,则读取终止,delim都不会被保存进s对应的数组中
第二种: 在中的getline函数有四种重载形式:
istream& getline (istream& is, string& str, char delim);
istream& getline (istream&& is, string& str, char delim);
istream& getline (istream& is, string& str);
istream& getline (istream&& is, string& str);
用法和上第一种类似,但是读取的istream是作为参数is传进函数的。读取的字符串保存在string类型的str中。
函数的变量:
is :表示一个输入流,例如cin。
str :string类型的引用,用来存储输入流中的流信息。
delim :char类型的变量,所设置的截断字符;在不自定义设置的情况下,遇到’\n’,则终止输入。
二、istringstream的用法
istringstream是一个比较有用的c++的输入输出控制类。
C++引入了ostringstream、istringstream、stringstream这三个类,要使用他们创建对象就必须包含这个头文件。
istringstream类用于执行C++风格的串流的输入操作。
ostringstream类用于执行C风格的串流的输出操作。
strstream类同时可以支持C风格的串流的输入输出操作。
istringstream的构造函数原形如下:
istringstream::istringstream(string str);
它的作用是从string对象str中读取字符。
#include
#include //istringstream 必须包含这个头文件
#include
using namespace std;
int main()
{
string str=“i an a boy”;
istringstream is(str);
string s;
while(is>>s)
{
cout<<s<<endl;
}
}
输出是:
i
am
a
boy
三、题目分析
首先我自己想的是先用getline输入,然后开n个队列,将不同进程的消息放进各自的队列中,然后开始循环找S和R对应的消息直到最终所有队列加起来的长度不再变化,但是只得了60分,时间复杂度太高了,超时,代码如下:
#include<iostream>
#include<queue>
#include<string>
using namespace std;
int main() {
int t, n;
cin >> t >> n;
queue<string> a[n];
string c;
string d;
getline(cin, d);
for (int i = 0; i < t; i++) {
int len = 0;
for (int j = 0; j < n; j++) {
getline(cin, c);
int m = c.length() / 3 + 1;
for (int k = 0; k < m; k++) {
string cc = c.substr(3 * k, 2);
a[j].push(cc);
}
}
for (int j = 0; j < n; j++) {
len += a[j].size();
}
while (true) {
for (int j = 0; j < n; j++) {
if (!a[j].empty()) {
string g = a[j].front();
if (g[0] == 'R' && !a[g[1] - '0'].empty()) {
if (a[g[1] - '0'].front()[0] == 'S' && a[g[1] - '0'].front()[1] - '0' == j) {
a[g[1] - '0'].pop();
a[j].pop();
}
}
else if (g[0] == 'S' && !a[g[1] - '0'].empty()) {
if (a[g[1] - '0'].front()[0] == 'R' && a[g[1] - '0'].front()[1] - '0' == j) {
a[g[1] - '0'].pop();
a[j].pop();
}
}
}
}
int sum = 0;
for (int j = 0; j < n; j++) {
sum += a[j].size();
}
if (sum == len) break;
len = sum;
}
if (len == 0) cout << 0 << endl;
else cout << 1 << endl;
for (int j = 0; j < n; j++) {
while (!a[j].empty()) {
a[j].pop();
}
}
}
return 0;
}
然后我自己又在网上找到了100分的代码,链接地址,代码中用到了递归来解决
主要是三个函数:
int exe(int no) 执行进程no
int receiveM(int from, int to) 进程from从进程to那里接收消息
int sendM(int from, int to) 进程from向进程to那里发送消息
输入完相应的信息后,在主函数中用一个for来判断各个进程的消息队列是否为空,如果都为空的话就不会发生死锁,否则将会导致死锁,在执行各个进程的时候,对其他进程的消息队列也会递归执行,代码如下:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<string>
#include<sstream>
#include<queue>
using namespace std;
const int MAXN = 10005;
struct Mes { //消息结构体
char flag; //R:收,S:发
int target; //目标进程
};
struct Pro { //进程结构体
queue<Mes> task; //消息队列
};
Pro pro[MAXN]; //进程数组,pro[i]代表进程i
int wait[MAXN]; //进程等待标志,1为等待,0为就绪
int exe(int no) {//执行进程no
if (wait[no] == 1) return -1; //如果进程处于等待状态,那么发生死锁
if (pro[no].task.empty()) return 0; //如果进程的消息队列为空,那么表示该进程成功结束
Mes cur = pro[no].task.front(); //取第一个消息
if (cur.flag == 'R') {
wait[no] = 1;
if (receiveM(no, cur.target) == -1) return -1;
//如果该消息成功执行
pro[no].task.pop();
wait[no] = 0;
if (exe(no) == -1) return -1; //递归处理该进程的下一个消息
return 0;
}
else if (cur.flag == 'S') {
wait[no] = 1;
if (sendM(no, cur.target) == -1) return -1;
//如果该消息成功执行
pro[no].task.pop();
wait[no] = 0;
if (exe(no) == -1) return -1; //递归处理该进程的下一个消息
return 0;
}
}
int receiveM(int from, int to) {//进程from从进程to那里接收消息
if (wait[to] == 1) return -1; //判断目标进程的状态
if (pro[to].task.empty()) return -1; //判断目标进程的消息队列是否为空
Mes cur = pro[to].task.front(); //获取目标进程的消息队列中的第一个消息,判断能否处理来自from的消息
if (cur.flag == 'R') { //不能处理
wait[to] = 1;
if (receiveM(to, cur.target) == -1) return -1; //递归处理目标进程的下个消息
wait[to] = 0;
pro[to].task.pop();
if (receiveM(from, to) == 0) return 0; //递归判断之前的消息能否得到处理
return -1;
}
else if (cur.flag == 'S') { //因为是'S',或许可以处理当前消息
if (cur.target == from) { //确实可以处理当前消息
pro[to].task.pop();
return 0;
}
//不能处理当前消息
wait[to] = 1;
if (sendM(to, cur.target) == -1) return -1; //递归处理目标进程的下个消息
wait[to] = 0;
pro[to].task.pop();
if (receiveM(from, to) == 0) return 0; //递归判断之前的消息能否得到处理
return -1;
}
return -1;
}
int sendM(int from, int to) {//进程from向进程to那里发送消息
if (wait[to] == 1) return -1;
if (pro[to].task.empty()) return -1;
Mes cur = pro[to].task.front();
if (cur.flag == 'R') {
if (cur.target == from) {
pro[to].task.pop();
return 0;
}
wait[to] = 1;
if (receiveM(to, cur.target) == -1) return -1;
wait[to] = 0;
pro[to].task.pop();
if (sendM(from, to) == 0) return 0;
return -1;
}
else if (cur.flag == 'S') {
wait[to] = 1;
if (sendM(to, cur.target) == -1) return -1;
wait[to] = 0;
pro[to].task.pop();
if (sendM(from, to) == 0) return 0;
return -1;
}
return -1;
}
int T, n;
int main() {
scanf("%d%d", &T, &n);
getchar();
for (int i = 0; i < T; i++) {
memset(wait, 0, sizeof(wait));
for (int j = 0; j < n; j++) { //初始化每个进程的消息队列
while (!pro[j].task.empty()) pro[j].task.pop();
}
for (int j = 0; j < n; j++) { //存储进程的消息队列
string line;
getline(cin, line);
istringstream ss(line);
string tmp;
while (ss >> tmp) {
Mes mes;
mes.flag = tmp[0];h
mes.target = tmp[1] - '0';
pro[j].task.push(mes);
}
}
int flag = 0;
for (int j = 0; j < n; j++) {
if (!pro[j].task.empty()) { //如果某个进程的消息队列非空,就执行该进程
if (exe(j) == -1) {
flag = 1;
break;
}
}
}
printf("%d\n", flag);
}
return 0;
}