CSP认证2022-09:如此编码、何以包邮?、防疫大数据,python满分解答代码

第27次CCF计算机软件能力认证前三题:如此编码、何以包邮?、防疫大数据,python满分解答代码。

目录

一、如此编码

题目背景

样例输入

样例输出

思路

代码

结果

二、何以包邮?

题目背景

样例输入

样例输出

​思路1

代码

思路2

代码

结果

三、防疫大数据

题目背景

样例输入

样例输出

思路

代码1

结果1

代码2

结果2


一、如此编码

题目背景

某次测验后,顿顿老师在黑板上留下了一串数字 23333 便飘然而去。凝望着这个神秘数字,小 P 同学不禁陷入了沉思……

d6e304d8b72841238f60b2a2e1c5e266.png

样例输入

15 32767
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2

样例输出

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

思路

f302717c38b14666ace95c8097a078f5.png

 192f229767ff4a99978da85775faabc4.png

代码

n,m=map(int,input().split())
# 由于ai是从下标为1开始的,故给a[0]设置为0
a_=[0]
#输入a[i]
for i in input().split():
    a_.append(int(i))

c_=[1]
#qian_zhui表示前i个a[i]乘积
qian_zhui=1
for i in range(1,n+1):
    qian_zhui=qian_zhui*a_[i]
    c_.append(qian_zhui)
# print(c_)
#一行公式搞定bi=(m%c_[i+1]-m%c_[i])/c_[i]
for i in range(n):
    print(int((m%c_[i+1]-m%c_[i])/c_[i]),end=' ')

结果

48cf1e1f5e3540d6a3bd3e34c66b3f89.png

二、何以包邮?

题目背景

新学期伊始,适逢顿顿书城有购书满 x 元包邮的活动,小 P 同学欣然前往准备买些参考书。
一番浏览后,小 P 初步筛选出 n 本书加入购物车中,其中第 i 本(1≤i≤n)的价格为 ai 元。
考虑到预算有限,在最终付款前小 P 决定再从购物车中删去几本书(也可以不删),使得剩余图书的价格总和 m 在满足包邮条件(m≥x)的前提下最小。

试帮助小 P 计算,最终选购哪些书可以在凑够 x 元包邮的前提下花费最小?

60d1b069a7804201acbf206dfce72087.png

样例输入

4 100
20
90
60
60

样例输出

110

0a35a2f37f1843448a98d47a7beb0783.png思路1

暴力枚举肯定超时,它在提示中也说了。

dd57227c1a4740c1812b453779e84751.png

所以得换个思路,其实这题可以看作背包问题,背包问题请参考:

python 01背包问题icon-default.png?t=N7T8https://blog.csdn.net/Renascence_6/article/details/115698776 01 背包问题描述:63a98be06edc4a128f8c521a0617d6bf.png

在本题中,我们可以把N件物品 看成书的数量即n,容量V则等价于满足包邮的条件x,第i件物品的体积和价值都看作 书的价格a_i。

但是我们所选书的总价值得大于或等于包邮条件x,故:

(1)总价值等于包邮条件x,输出res

(2)总价值小于包邮条件x,说明当前所选书价值之和,再加上任意一本书籍的价值将超过包邮条件,故我们只要在所剩书籍中选择最小价值的书籍,就能包邮且花费最小

代码

n,x=map(int,input().split())
books=[int(input()) for i in range(n)]
num=10*6+1
v=[0]*num
w=[0]*num
f=[[0]*num for i in range(num)]
#第i件物品的体积和价值都看作 书的价格a_i。
for i in range(1,n+1):
    v[i]=books[i-1]
    w[i]=books[i-1]
#01背包问题模板
# ------------------------
for i in range(1,n+1):
    for j in range(x+1):
        f[i][j]=f[i-1][j]
        if j>=v[i]:
            f[i][j] = max(f[i][j], f[i - 1][j - v[i]]+w[i])
res=0
for i in range(x+1):
   res=max(res,f[n][i])
# -------------------------
b=x
result=books
#去除掉已选书籍
for i in range(n,0,-1):
    if f[i][b]>f[i-1][b]:
        result.remove(v[i])
        b-=w[i]
#判断
if res<x:
    print(min(result)+res)
else:
    print(res)

思路2

(1)利用01背包问题的通解,计算出每一种情况的总价值,然后遍历dp中的数值,如果大于等于包邮条件的价格,即输出结果。

代码

n,x = list(map(int,input().split()))
A = []
for i in range(n):
    data = int(input())

    A.append(data)
#两种情况,选择该物品或不选该物品
#使用动态规划
max_value = sum(A)
#必须先遍历物品,再遍历背包
dp = [0]*(len(A)*x)#n乘以x
for i in range(len(A)):
    for j in range(max_value,A[i]-1,-1):
        dp[j] = max(dp[j],dp[j-A[i]]+A[i])
# print(dp)
for k in dp:
    if k>=x:
        print(k)
        break

结果

2eda4828d143433f9e00cea45c5eec03.png

三、防疫大数据

题目背景

近期,国内 COVID-19 疫情多点散发,西西艾弗岛的防疫形势也异常严峻。西西艾弗岛疫情防控指挥部决定在岛上建立一套疫情风险监测系统。这套风险监测系统的主要功能是,收集手机用户到访地区的信息,根据用户的到访地区,判断用户的疫情风险。具体而言,在每天夜里,西西艾弗岛大数据运行管理中心都会收到一批手机用户到访地区的信息,以及当天疫情风险地区的信息。数据中心需要根据这些信息,生成一份存在风险的手机用户的名单,提供给疫情防控指挥部,以便进行后续的疫情防控工作。

f34530c2ba564fb28750101143a492c0.png

420137c49f9540559777aceff598ff26.png

样例输入

9
1 4 1
0 1 1
-1 1 1
-1 2 1
0 2 2
0 3
0 3 1
1 2 2
1 3 2
0 0
0 0
0 0
0 0
0 0
0 1
5 4 1
1 0 1

样例输出

0 1
1 1 3
2 1 3
3 1 3
4 1 3
5 1 3
6 1 3
7
8

思路

(1)首先分析第一行,从中可以提取出以下几个要点:

  1. 日期是连续的整数
  2. 题目中将要处理漫游数据,结构为<d,u,r>,为此可以设计一个结构体(c++)或类(python)来定义漫游数据,在python中可以定义如下:
    class Message:
        def __int__(self):
            self.day = None
            self.user = None
            self.area = None

42289f0df1af4ea6be06e535b91e56d5.png

(2)观察漫游数据的类型和列入风险名单的条件,可以得到以下信息:

  1. 延迟数据,如果延迟时间超过7天,就不需要处理它了,因为它不满足列入风险名单的第一个条件
  2. 重复数据,在读取数据时,应该对数据进行判断,若之前出现过,则不需要处理它。当然也可以忽视该要求,因为最终的输出结果只需要输出用户id,是否有重复数据不影响最终结果
  3. 若到访当天,所到访的地区不处于风险状态,也不需要处理它了,否则需要进一步处理
  4. 若从到访日生成名单当日,只要有一天该地区不处于风险状态,那么该用户不会被纳入风险名单中,所以在此处需要加一个地区连续风险的判断

a7eb92670f5f4280b519d5395c06b21d.png

812eb8d7a3e84b14a16291a4bf9c2504.png

(3)观察输出要求,结果是需要从小到大排序的存在风险的用户列表,为此,在结果的输出时应考虑去除重复的用户id以及利用sort进行排序

cfcbd25b35b84df88aec0b237e1a2b71.png

代码1

# 风险地区字典
Danger_Area = {}  # 内容为 {日期_地区:1,日期_地区:1}  作用:用以记录风险地区
n = int(input())
datas = []  # 用以存放漫游数据,每一个元素包含date、user、area、发布日期
result = {} #存放结果,方便统一输出
for i in range(n):
    result[i] = []#初始化结果字典
for i in range(n):
    # 第i天的数据
    data_i = list(map(int, input().split()))
    ri = data_i[0] #当日收到的风险地区信息的数量
    mi = data_i[1] #当日收到的漫游数据的条目数量
    if ri == 0:  # 如果当日收到的风险地区信息的数量为0
        pij = []  #则当日收到的风险地区的列表为空列表
    else:
        pij = data_i[2:]#否则读取漫游数据中 当日收到的风险地区的列表
        for d in range(7):#从当日开始,到第6日(包括),该地区都是风险地区
            for k in range(len(pij)):#读取 当日收到的风险地区列表中的 每一个 地区
                keys = str(i + d) + '_' + str(pij[k])  # 将日期和地区拼起来,存入字典中,方便后续的查询
                Danger_Area[keys] = 1#为了简单起见,设置其值为1,当然也可以使用其他值
    # 读取mi行漫游数据,将数据都存放到datas中,之后统一处理。
    # 为什么这样处理?因为数据中存在延迟数据,当日收到的漫游数据,在未来输出风险名单列表时会用到
    for j in range(mi):
        d_1, user, area = list(map(int, input().split()))
        date_area = str(d_1) + '_' + str(area)#将到访日期和地区拼起来,查询Danger_Area字典
        value = Danger_Area.get(date_area)
        if value != 1:#如果到访当日,该地区不是风险地区,这条漫游数据就没有用了。因为根据列入风险名单的第二个条件:该用户在近 7 日内到访的地区在《到访的那一日处于风险状态 》
            continue
        if i-d_1>=7:#到访当日据风险名单发布日期已经超过了7天,该条数据也作废。因为根据列入风险名单的第一个条件可知
            continue
        #得到一条数据,# date user area 发布日期
        data_i_j = []
        data_i_j.append(d_1)
        data_i_j.append(user)
        data_i_j.append(area)
        data_i_j.append(i)
        datas.append(data_i_j)
#开始处理所有的漫游数据
for data in datas:
    # 条件先摆在这:
    # 该用户在近7日内曾经出现在接收到的漫游数据中,并且近7日内有到访某个地区的记录;
    # 该用户在近7日内到访的地区在到访的那一日处于风险状态;
    # 上述存在风险的地区自到访日至生成名单当日持续处于风险状态。
    d_1, user, area, d_0 = data
    if d_1<0:#若到访当日 日期小于0,则该条数据中的用户不可能出现在风险名单中,因为风险名单发布日期是非负的,这意味着小于0的到访当日所访问的地区一定不是风险地区(因为都没发布风险地区名单呢)
        continue
    for d in range(d_0,n):#从发布日期d_0开始,处于风险名单中用户要被连续发布几日,但是日期d值不会超过n
        # d表示发布名单日
        if d-d_1>6:#发布日期超过到访日期7日,则跳出循环
            break
        tag = True#用以判断area从d_1 到 d 日是否连续为风险地区
        for k in range(d_1,d+1):#判断是否连续到访
            date_area = str(k)+'_'+str(area)
            value = Danger_Area.get(date_area)#第k日 area地区是否是风险地区
            if value!=1:
                tag = False#有一天不是风险地区,则跳出循环
                break
        if tag:
            result[d].append(user)
#输出结果
for key in result.keys():
    result_i_set = sorted(set(result[key]))
    print(key, end=' ')
    for e in result_i_set:
        print(e, end=' ')
    print()

结果1

33b7292c36ae45cf9a0132fe596eea22.png

代码2

感觉之前的代码有点儿繁琐,空间开销比较大,可以进行优化一下,代码如下:

class Message:
    def __int__(self):
        self.day = None
        self.user = None
        self.area = None
n = int(input())
danger_area = {}#key存放地区,value存放[开始时间,结束时间]
datas = {}  # 用以存放有效数据 每一个元素包含date、user、area
result = {}
for d in range(n):
    result[d] = []
    datas[d] = []
    data_i = list(map(int, input().split()))
    ri = data_i[0]
    mi = data_i[1]
    if ri == 0:  # 判断是否为0
        pij = []  # 使用一个空列表
    else:
        pij = data_i[2:]#风险区域列表
    for a in pij:
        #如果a之前不是风险地区或者d-1天时x已经不是风险地区
        if not danger_area.get(a) or d-danger_area.get(a)[1]>1:
            danger_area[a]=[-1,-1]
            danger_area[a][0] = d#记录开始时间,开始时间和结束时间是不同步的
        danger_area[a][1] = d+6#更新记录结束时间
    #处理漫游数据
    for i in range(mi):
        d_1, user, area = list(map(int, input().split()))
        #如果area在当天不是风险地区,漫游信息中的地点也不是风险地区(没有在danger_area的key中),或者是7天前的无效信息
        if not danger_area.get(area) or danger_area.get(area)[1]<d or 6<d-d_1:
            continue
        data = Message()
        data.area=area
        data.day = d_1
        data.user = user
        datas[d].append(data)
    #处理漫游数据
    for i in range(max(0,d-6),d+1):#处理[d-6,d]天中收到的有效漫游信息
        if not datas.get(i):
            continue
        for data in datas[i]:#遍历第i天内的消息
            d_1,user,area = data.day,data.user,data.area
            #满足以下条件才输出结果
            '''
            1.当前区域是风险地区
            2.漫游信息是7天内收到的
            3.[d1,d]这个时间段这个地区都是风险地区
            '''
            if danger_area.get(area) and 6>=d-d_1 and d_1>=danger_area.get(area)[0] and danger_area.get(area)[1]>=d:
                result[d].append(user)
for key in result.keys():
    result_i_set = sorted(set(result[key]))
    print(key, end=' ')
    for e in result_i_set:
        print(e, end=' ')
    print()

结果2

6834afb250f34d8aaaaed6cc51f68d63.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值