CCF CSP认证 历年题目自练Day47

题目

试题编号: 201712-3
试题名称: Crontab
时间限制: 10.0s
内存限制: 256.0MB
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
样例输入
3 201711170032 201711222352
0 7 * * 1,3-5 get_up
30 23 * * Sat,Sun go_to_bed
15 12,18 * * * have_dinner
样例输出
201711170700 get_up
201711171215 have_dinner
201711171815 have_dinner
201711181215 have_dinner
201711181815 have_dinner
201711182330 go_to_bed
201711191215 have_dinner
201711191815 have_dinner
201711192330 go_to_bed
201711200700 get_up
201711201215 have_dinner
201711201815 have_dinner
201711211215 have_dinner
201711211815 have_dinner
201711220700 get_up
201711221215 have_dinner
201711221815 have_dinner

题目分析(个人理解)

  1. 首先此题是基于字符串处理的模拟题,根据题目的描述,我们要对输入的所有内容进行标准化,星期,月份都可以用任意大小写的字母的缩写或者数字表示具体内容,由于输入的第一行也就是开始时间和结束时间采用数字表示,所以,我将在后面输入的命令也全部标准化为数字,注意星期从0(表示周天)开始,到6。月份从1开始到12
  2. 由于本题处理内容较多,我采用函数对方法封装,对于处理星期和月份标准化的函数,如果实参是int则直接返回,如果是英文字母则全部转换为小写之后可以根据位序返回具体的值
  3. 接下来处理命令,对于命令有以下一些特殊字符,逗号表示并的关系,-表示开始结束(如果是星期的位置,1,3-5表示周一,周三,周四 ,周五),星号表示所有。(月份同理)尤其注意重复的情况,比如:3,1-5需要进行去重,不然后面会出现重复输出的情况,由于我全部用列表存储,那么可以直接用list(set())去重。(元组值的唯一性),分钟小时星期是同样的标准化方法
  4. 标准化完成后,要进行判断,判断命令是否在第一行输入的给定的时间范围之内,数字化标准后,只需要用数值判断范围即可。如果命令的时间不在此区间则直接跳过判断下一个命令,还要判断每个月的日期是否正常,比如11月31日这种,还要判断星期是否正常:比如2023年11月18日是周五(实际上是周六)
  5. 对于日期数是否正常,只用判断该日期是否小于这个月的最大日期数,由于2月因为闰年有特殊性,因此分为闰年和非闰年分别判断,对于星期,我们根据题目条件已知1970年1月1日是周四,所以我们可以推算出对应的星期(已知年月日推星期,这我在前面的打卡中也遇到过此类题目)。只需算出19700101到命令的执行日期的总天数对7取余数(算出多少周)再加四,再对7取余即可得知星期。我们扩展一下,如果不给1970年1月1日是周四阁下该如何应对?大家可以搜一下蔡勒公式。
  6. 上代码!!!
# crontab
Days_of_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]#不是闰年
Days_of_mons_in_leap_year = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]#闰年
Month_string_list = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
Weekday_string_list = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']


def m_string2int(m):  # 将所有月份全部转化为数字
    try:
        a = int(m)
        return a
    except:
        for i in range(12):
            if (m.lower() == Month_string_list[i].lower()):  # 使用.lower()函数转换为小写
                return i + 1


def w_string2int(w):  # 将所有星期全部换为数字
    try:
        a = int(w)
        return a
    except:
        for i in range(7):
            if (w.lower() == Weekday_string_list[i].lower()):  # 使用.lower()函数转换为小写
                return i


def ddmm(day, mon):  # 闰年的2月29天,1 3 5 7 8 10 12 31days ,其他30days
    # d为输入天的字符串,m为输入月份的字符串
    # start为开始的天,end为结束的天
    # 函数返回所有符合条件的天的list
    day_mon_set = []
    dayset = []
    days = day.split(',')  # 逗号是并的关系
    for d in days:
        if (d == '*'):
            dayset = list(i + 1 for i in range(31))
        elif (len(d.split('-')) != 1):
            s, e = list(map(int, d.split('-')))
            for i in range(s, e + 1):
                dayset.append(i)
        else:
            dayset.append(int(d))
    dayset=list(set(dayset))#去重,如果出现3,1-5的情况避免重复输出3
    mons = mon.split(',')#逗号是并的关系
    monset = []
    for m in mons:
        if (m == '*'):
            monset = list(i + 1 for i in range(12))
        elif (len(m.split('-')) != 1):
            s, e = m.split('-')
            for i in range(m_string2int(s), m_string2int(e) + 1):
                monset.append(i)
        else:
            monset.append(m_string2int(m))
    monset=list(set(monset))#去重,如果出现3,1-5的情况避免重复输出3
    for x in monset:
        for y in dayset:
            day_mon_set.append(x * 100 + y)#11月12日就是1112
    return day_mon_set#返回月日的格式


def MMHH(mm, hh):#分钟小时标准化
    min_hour_set = []
    minset = []
    hourset = []
    mms = mm.split(',')
    for m in mms:
        if (m == '*'):
            minset = list(i for i in range(60))
        elif (len(m.split('-')) != 1):
            s, e = list(map(int, m.split('-')))
            for i in range(s, e + 1):
                minset.append(i)
        else:
            minset.append(int(m))
    minset = list(set(minset))  # 去重,如果出现3,1-5的情况避免重复输出3
    hhs = hh.split(',')
    for h in hhs:
        if (h == '*'):
            hourset = list(i for i in range(24))
        elif (len(h.split('-')) != 1):
            s, e = list(map(int, h.split('-')))
            for i in range(s, e + 1):
                hourset.append(i)
        else:
            hourset.append(int(h))
    hourset = list(set(hourset))  # 去重,如果出现3,1-5的情况避免重复输出3
    for h in hourset:
        for m in minset:
            min_hour_set.append(h * 100 + m)
    return min_hour_set


def day_of_week(ww):#标准化星期
    if (ww == '*'):
        return list(i for i in range(7))
    else:
        dset = []
        wws = ww.split(',')
        for w in wws:
            if (len(w.split('-')) != 1):
                s, e = w.split('-')
                for i in range(w_string2int(s), w_string2int(e) + 1):
                    dset.append(i)
                dset = list(set(dset))  # 去重,如果出现3,1-5的情况避免重复输出3
            else:
                dset.append(w_string2int(w))
                dset = list(set(dset))
        return dset


def check(ymhdmw):#检查给定的开始时间和事件进行的时间之间是否是包含的关系
    normal = []
    for X in ymhdmw:
        year, mon_day, hour_min, weekday, com = X
        # 检查是否在设置的时间范围内
        time = year * 100000000 + mon_day * 10000 + hour_min#标准化
        if (time < start or time >= end):
            continue

        # 检查每个月的日期数是否正常
        if ((year % 4) == 0):#闰年
            daysbefore = sum(Days_of_mons_in_leap_year[0:mon_day // 100 - 1])#计算到前一个月总共有多少天,比如:1116,计算的就是从1月到10月总共的天数
            if (Days_of_mons_in_leap_year[mon_day // 100 - 1] < (mon_day % 100)):
                continue
        else:#不是闰年
            daysbefore = sum(Days_of_month[0:mon_day // 100 - 1])
            if (Days_of_month[mon_day // 100 - 1] < (mon_day % 100)):
                continue

        # 检查星期数是否正常
        years_from_1970 = year - 1970#1940到输入的年份有多少年
        num_of_leap_year = (years_from_1970 + 1) // 4#计算1970年之后有多少个闰年
        days_from_197011 = years_from_1970 * 365 + num_of_leap_year + daysbefore + mon_day % 100 - 1#计算1970年1月1日至输入的那天有多少天
        if (((days_from_197011 % 7) + 4) % 7 == weekday):#题目给了1976年1月1日是周四,接下来推算即可,可以判断某年某月某日是不是某星期
            normal.append([time, command])#将判断符合逻辑的时间和命令写入列表
    return normal


n, start, end = list(map(int, input().split()))
crontab = []
startyear = start // 100000000
endyear = end // 100000000
for i in range(n):
    minutes, hours, day_of_month, month, dayofweek, command = input().split()
    minhoueset = MMHH(minutes, hours)
    daymonset = ddmm(day_of_month, month)
    week = day_of_week(dayofweek)
    ymhdmw = []
    for i in range(startyear, endyear + 1):
        for mh in minhoueset:
            for dm in daymonset:
                for w in week:
                    ymhdmw.append([i, dm, mh, w, command])
    crontab.append(check(ymhdmw))
crontab1 = []
for X in crontab:
    for x in X:
        crontab1.append(x)
crontab2 = sorted(crontab1, key=lambda x: x[0])
for i in crontab2:
    print(i[0], i[1])

总结

请添加图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尚.西西弗斯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值