问题描述
中国有句俗语叫“三天打鱼两天晒网”。某人从1990年1月1日起便开始“三天打鱼两天晒网”,问这个人在以后的某一天中是“打鱼”还是“晒网”。
分析
“三天打鱼两天晒网”总共是五天,也就是说五天一个循环,在循环里,头三天这个人在打鱼,后两天这个人在晒网,于是我们只要知道从1990年1月1日起到需要询问的某一天为止过去了多少天,用天数对5取余数,得到的结果分别去对应:0-打鱼、1-打鱼、2-打鱼、3-晒网、4-晒网,就能知道这个人在那一天是“打鱼”还是“晒网”。
于是相应的,题目就转化成从询问某一天距离1990年1月1日过去了多少天。
对于时间的处理,Python自带的模块比如datetime就可以快速完成,所以就本题而言,如果用Python,除去输入输出的代码,也就是一句话的事。
import datetime
act = ["打鱼","打鱼","打鱼","晒网","晒网"]
start = datetime.datetime(1990,1,1)
year,month,day = map(int,input().split())
days = (datetime.datetime(year,month,day) - start).days # 计算过去了多少天
print(f"他在{act[days%5]}")
顺便提一句,dateime是内置模块,模块中有个datetime的类,用于表示某一天(可以精确到秒),还有个timedelta的类,表示两个datetime的距离(时间差)。而这个timedelta有两个属性:days和seconds。使用days就可以直接得出两个日期之间距离多少天,不满24小时的时间会保存在seconds属性里,也就是说seconds并不是指两个日期之间总共距离多少秒,而是减去所有整天后剩下多少秒。
回到题目,显然这一题问的是怎样计算两个日期之间的距离,虽然问哥不提倡重复造轮子,但是如果时间允许,倒是可以拿来做做练习。
让我们来思考一下,计算两个公历日期之间有多少天是什么步骤,
- 首先要知道两个日期之间差了多少年;
- 其次要看距离不够一年的时间里有哪几个月;
- 最后再查看不够一个月的时间里还差多少天。
由于本题的起始日期是一年的头一天,所以第2和第3点等于白给,在不考虑查询的日期是否有误的情况下(比如输入2022年13月32日),难度只在于注意闰年平年、大小月的天数不同。
对于闰年,我们已知判读条件有两个:1、能被400整除;2、能被4整除但不能被100整除,所以可定义一个函数用来判断某一年是否是闰年。然后遍历从1990年开始到输入的年份,如果是闰年就加366天,平年就加365天。
计算完年份差,再继续计算差了哪几个月。因为起始日期是1月,所以输入的月份之前都是要累加天数的范围。比如输入的月份是5,则要加上1、2、3、4,四个月的天数。循环最大到11,因为如果输入的月份是12,我们也无法把它看作整月,而如果输入的月份是1,我们只要加上整年的天数即可,所以12是不用检查的。
最后,我们只要加上不足一个月的天数即可,因为起始日期是1号,所以我们直接用输入的日期减去1,得到天数,然后累加在一起即可。
完整代码如下:
def isLeapYear(y):
return True if y%4==0 and y%100!=0 or y%400==0 else False
months = [31,28,31,30,31,30,31,31,30,31,30,31]
act = ["打鱼","打鱼","打鱼","晒网","晒网"]
year,month,day = map(int,input().split())
days = 0
for y in range(1990, year):
days += 366 if isLeapYear(y) else 365
for m in range(1, month): # 此处的month-1是减去起始月份,也就是距离1月有哪几个月
if m in [1,3,5,7,8,10]: # 大月
days += 31
elif m in [4,6,9,11]: # 小月
days += 30
elif isLeapYear(year): # 闰年的二月
days += 29
else:
days += 28
days += day-1 # 同理,此处day-1也是减去起始天,距离1号有几天
print(f"他在{act[days%5]}")
当然,本题还有很多写法,比如先给1到12月定义一个天数的列表或字典,然后在遍历的时候调取等等,思路大同小异,不再赘述。
输出
2022 10 1
他在打鱼
2011 10 2
他在晒网
2011 10 3
他在打鱼