PTA天梯赛:L1-043 阅览室 (详解及分析)

题目大意:

要你设计一个借阅记录系统功能如下:

借书(S)时记录借书时间,还书(E)时记录还书时间。

每本书有一个编号(不相同)编号范围为1~1000

当编号为0时代表管理员今天下班了

此时要你输出这一天有效借书次数以及平均阅读时间

我们对有效的定义为:

一天内有借且有还。

无效的定义为:

有借无还无借却还

我们会忽略这两种记录。

注意输出平均时间是分钟数的四舍五入

样例:

输入:

3
1 S 08:10
2 S 08:35
1 E 10:00
2 E 13:16
0 S 17:00
0 S 17:00
3 E 08:10
1 S 08:20
2 S 09:00
1 E 09:20
0 E 17:00

输出:

2 196
0 0
1 60

思路分析:

1.会给出一共几天,那么我们需要一个变量来记录天数,以便结束循环。因为0为一天的结束,所以记录0的数量即可。

2.每一本书有借书时间,这个时间包括小时和分钟,所以我选择用结构体储存他的时间(结构体相当于把他们结合成一个成员,用两个数组分别储存效果虽然一样,但是有时候会糊住你的思路)。

3.它对有效的定义是有借有还,那么我们只需要在遇到还书操作时查询此书是否曾被借阅且还没还书,由此引出一个新问题:

4.我们要查询书是否被借过:那么我们需要对书有一个标记(此时我们可以笼统的认为在书的结构体中储存一个标记,借时标记为1,未借默认0)那么我们在还书时即可直接查询此标记得知此书是否被借

5.在查询结果成功后,那么此时有借有还所以借书次数+1,注意此时你还书了,那么书应该回到未借状态即标记为0。然后累计出从借到还的时间:time=(还书h-借书h-1)*60+(60-借书m)+还书m。将每次合法都累加起来就是一天的总借阅时间。

6.当遇到0编号时代表一天的结束:此时输出有效借书次数和平均时间(总时间/次数)

那么大致思路就是这样了,接下来是细节处理:

那么以上思路是有bug的:

1.如果遇到多次借一次还

2.遇到一次借多次还

3.昨天有借记录没有还记录,今天有还记录没有借记录

4.初始化问题

其实很简单也很巧妙

代码里说:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<cmath>
#include<stack>
#include<iomanip>//头文件,不一定都用上了

using namespace std;
typedef long long llint;
const int N=1e5;//一些预处理

struct Node{
	int h;
	int m;
	int v;
	Node(){//结构体重构(书面名字罢了)
//反正记住你需要初始化结构体的话就得这样写,结构体名即函数名。
		h=0;
		m=0;
		v=0;
	};
}s[1050];//借书结构体:h代表时间的小时,m代表时间的分钟,v为标记此书是否被借

int myround(double x){//四舍五入函数;题目要求结果四舍五入
	double a=floor(x);//x的向下取整
	double b=ceil(x);//x的向上取整
	if(x-a<b-x){//看离哪边更近(0.5很特殊,离两边一样近,但我们将他列入5入规则)
		return (int)a;//如果离a近返回a
	}
	return (int)b;//否则就是b
}

//以上都是一些辅助定义罢了,看起来长而已,接下来按照思路来看看主函数吧!
int main(){
	int n;
	cin >> n;//n为天数
	int k=0;//k用来记录天数
	int ansn=0,ansf=0;//ansn和ansf分别记录有效借书次数和有效总阅读时间

	while(k<n){//还没到n天就继续
		int a;
		char c;//a代表编号c代表借(S)或者还(E)
		int l,r;//l代表小时,r代表分钟
		cin >> a >> c;
		scanf("%d:%d",&l,&r);

		if(a==0){//一天结束了
			if(ansn)//避免分母为0
			cout << ansn << " " << myround(ansf/(ansn*1.0)) << endl;//输出次数和平均时间
			else//没有人借书
			cout << 0  << " " << 0 << endl;
			ansn=ansf=0;//每一天独立计算所以当今天结束就初始化
			k++;//迎来下一天
			continue;//不需要记录此状态,跳过
		}

		if(c=='S'){//借书操作
			s[a].h=l;//记录小时
			s[a].m=r;//记录分钟
			s[a].v=k+1;//重点:标记的加强
//解释一下为什么如此标记:
//此处的标记记录的是:这是第几天的借书记录
//如此即可避免前一天借书未还记录与后一天未借还书的组合
//因为我们根据标记得知他们不是一天的
		}

//以上借书操作也规避了多次借一次还
//每次都记录的是离还最近的一次借

		else{//还书操作
			if(s[a].v!=k+1)continue;//今天都没有借过这本书,那么还书就不生效
			s[a].v=0;//借过了,又还了,所以回归未借状态,避免一次借多次还。
//因为此时书的状态变成了未借,自然还书不合法。
			ansn++;//有效借书+1
			ansf+=(l-s[a].h-1)*60+(60-s[a].m)+r;//累加今天的总时间
		}
	}
	return 0;
} 

很有趣的题,虽然有点折磨。

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值