2021年软件类第十二届蓝桥杯 省赛 python组 A-E题解

简介: 2021年软件类第十二届蓝桥杯 省赛 python组 A-E题解

这里面的题目都可以从https://www.lanqiao.cn/courses/2786/learning/?id=280833得到,写了一些python的解法

除了本身的题解之外,也可以配套视频看一下吧,在我空闲之余做了这个的讲解,希望对大家有帮助,B站讲解视频


试题 A:卡片


cf07913cc7634c409d8a86ef412f0bc2.png

思路


对于这道题来说,我局的思路还是比较清晰的,我们首先知道自己的卡片个多少张,我们可以利用一个哈希表,只要我们在拼一个数字的时候,我们的哈希表的值为0了,也就是我们的客片不够了,我们就直接输出我们的结果


对于python来说,我们可以很容易的去用我们的字典,我们的字典就是我们的哈希表,代码还是很简单的


代码

# https://www.lanqiao.cn/problems/1443/learning/
h = {}
n = 2021 # 卡片的数目
for i in range(10):
    h[str(i)] = n # 定义每张卡片的数目
flag = True
i = 0
while flag:
    i += 1
    for x in str(i):
        h[x] -= 1 # 拼x这个数需要用掉一张卡片
        if h[x] < 0: # 卡片少于0,说明第i张卡片拼不了
            flag = False
            break
print(i-1)

答案


3181


试题 B:直线


064d7b443bbd475d8b335d8a80fee52c.png


思路


对于这道题来说,我们就需要根据我们学的数学公式,也就是我们的斜率和截距公式


对于每一条直线来说,最重要的就是他的斜率和截距,如果我们单单以斜率来看的话,就忽略了截距,所以两者都需要考虑,除此之外,我们还需要考虑的就是特殊情况,即斜率不存在的情况


所以我们就可以遍历所有的点,对于我们的任意两点是可以组成一条直线的,我们记录他的斜率和截距,最后我们再加上我们没有计算的斜率不存在的情况,斜率不存在的情况也很简单,就是我们的x坐标的范围,在这道题就是20。


代码

#直线
points=[[x,y] for x in range(20) for y in range(21)] #创建二维列表:代表xy坐标系
docker=set()                            #创建集合属性的容器:因为集合里的元素不会重复
for i in range(len(points)):            #二重循环遍历每个坐标
    x1,y1=points[i][0],points[i][1]     #注意书写格式:a,b=c,d
    for j in range(len(points)):
      x2,y2=points[j][0],points[j][1]
      if x1==x2:                        #特殊情况:直线垂直时斜率不存在,先跳过最后计算
          continue
      k=(y2-y1)/(x2-x1)                 #斜率公式
      b=(x2*y1-x1*y2)/(x2-x1)           #截距公式
      if (k,b) not in docker:           #存入容器里没有的(斜率,截距)对
          docker.add((k,b))
print(len(docker)+20)                   #输出结果:容器的长度40237+斜率不存在的20种情况=40257


答案


40257


试题 C:货物摆放


e627f2100a02481696e1450ee8749ac9.png


思路


这道题说简单也简单,不简单也不简单,如果用穷举的方法,用python不知道要猴年马月才能算出来


所以我们就要用聪明一点的方法,比如我们可以首先得到我们的n的约数,之后来说,就是这些约数的组合了,因为我们肯定要保证长宽高是我们的n的约数的,要不然不可能可以满足题目条件


接着我们就可以对约数进行一个组合,如果组合结果相乘是n的话,我们就可以把方案输出


tips:其实对于这道题来说,我们还可以利用分解质因数的方法,这个方法就可以在1s内输出结果,简单来说,就是会对我们的n分解质因数,对于分解的质因数我们也可以进行组合变成我们的因数,最后结果相乘就是我们的n,因为都是分解质因数得来的结果。


代码

n=2021041820210418              #货物数量
ans=0                           #初始统计值为0
docker=set()                    #创建集合属性的容器
for i in range(1,int(n**0.5)+1):#循环遍历,筛选n的约数(对n开根号是为了加快速度)
    if n%i==0:
        docker.add(i)           
        docker.add(n//i)
for i in docker:                #三重循环遍历容器(放心,三重不慢,运行5s就出结果)
    for j in docker:
        for k in docker:
            if i*j*k==n:        #满足条件,方案数+1
                ans+=1
print(ans)                      #输出结果:2430

答案


2430


试题 D:路径

d45ab2033e5946cc8ece69fae5117031.png


思路


这道题还是比较简单得到,我们可以看到这个是一个无向图,我们可以直接用动态规划的思想,也就是DP的思想来解决,首先我们可以看到条件,两个节点,如果差的绝对值大于21,就无边先连,否则,就用长度为最小公倍数的无向边相连。


我们求的是最短路径,首先我们就可以遍历差为21的数,这里就是用二层循环表示,最后我们再用dp的方式,这个动态转移的方法还是简单的,两种情况,直接用当前的数,或者加上最小倍数的长度,这两者的最小值就是我们的最短路径的长度


image.png

代码

import math
# 最小公倍数模板
def lcm(a,b):
    return a*b//math.gcd(a, b)# 利用内置函数
dp = [float('inf')]*(2021+1)
dp[1] = 0 # 节点从0开始
for i in range(1,2021+1): # 1 -> 2021
    for j in range(i+1,i+21+1): # 差为21
        if j > 2021:
            break
        dp[j] = min(dp[j],dp[i]+lcm(i, j)) # 动态转移方程
print(dp[2021])

答案


10266837


试题 E:回路计数


68795fdac329468bbf18071cc689de17.png

思路


这道题主要的思路就是状态压缩的动态规划,简称状压DP

简单来说,我们可以用二进制来代表我们的21个状态,加入我们有4栋教学楼,那么我们访问所有教学楼就是1111(二进制),初始状态是从第一个教学楼走的,也就是初始状态为1000,利用这样的方法,如果有n栋教学楼,我们就有1<<n种状态,这道题就是2的21次方个状态


除此之外,我们还需要一个记录两个教学楼是否互通,就是判断两者的最大公因数是否为1


最后我们就可以用这道题的核心,也就是我们状态压缩DP,对于这个状压DP来说,我们的想法就是,d p [ i ] [ j ] dp[i][j]dp[i][j]对于状态i,i的二进制表示中为1的位置,表示走过了教学楼 j


我们会枚举每一个状态,对于每一位来说,我们都会判断状态i是否包含第j栋教学楼,如果包含的话,就会进行判断其他位,枚举所有可能从教学楼k走到教学楼j的情况,加入我们的状态i除去j后还包含j的话,我们就可以加入其中的方案


image.png

最后我们就可以得到所有的方案,不过要减去j状态为0时候的方案,因为我们一开始就是从0,也就是第一件教学楼出现的。


代码

import os
import sys
from math import gcd
n = 21
m = 1 << n # 一共有2的21次方个状态
dp = [[0]*n for i in range(m)] # dp[i][j]对于状态i,i的二进制表示中为1的位置 表示走过了教学楼j
load = [[False]*n for i in range(n)] # 存储i, j之间是否有路
for i in range(1,n + 1):
    for j in range(1,n + 1):
        if gcd(i, j) == 1:
            load[i-1][j-1] = True
dp[1][0] = 1 # 表示初始状态,也就是第二个状态 0000...0001 第一位为1
for i in range(1,m): # 枚举每一个状态 
    for j in range(n): # 对每一位 判断状态i是否包含第j栋教学楼
        if i >> j & 1: # 如果第j+1位为1
            for k in range(n): # 判断其他位 枚举所有可能从教学楼k走到教学楼j的情况
                if (i - (1<<j)) >> k & 1 and load[k][j]:  # 判断状态i除去j后是否包含k
                    dp[i][j] += dp[i-(1<<j)][k]
print(sum(dp[m-1]) - dp[m-1][0])


答案


881012367360

相关文章
|
3天前
|
Python
Python 一步一步教你用pyglet制作可播放音乐的扬声器类
Python 一步一步教你用pyglet制作可播放音乐的扬声器类
14 0
|
10天前
|
Python
python面型对象编程进阶(继承、多态、私有化、异常捕获、类属性和类方法)(上)
python面型对象编程进阶(继承、多态、私有化、异常捕获、类属性和类方法)(上)
52 0
|
10天前
|
索引 Python
python 格式化、set类型和class类基础知识练习(上)
python 格式化、set类型和class类基础知识练习
33 0
|
11天前
|
Python
python学习12-类对象和实例对象
python学习12-类对象和实例对象
|
13天前
|
Web App开发 测试技术 网络安全
|
1月前
|
Python
Python类(class)中self的理解
Python类(class)中self的理解
19 0
|
1月前
|
Python
Python类定义:从小白到专家的旅程
Python类定义:从小白到专家的旅程
8 0
|
1月前
|
Python
Python类与对象:深入解析与应用
本文介绍了Python中的核心概念——类和对象,以及它们在面向对象编程中的应用。类是用户定义的类型,描述具有相同属性和行为的对象集合;对象是类的实例,具备类的属性和方法。文章通过示例讲解了如何定义类、创建及使用对象,包括`__init__`方法、属性访问和方法调用。此外,还阐述了类的继承,允许子类继承父类的属性和方法并进行扩展。掌握这些概念有助于提升Python编程的效率和灵活性。
|
1月前
|
存储 UED 开发者
Python语言的软件打包及发布
Python语言的软件打包及发布
|
1月前
|
机器学习/深度学习 设计模式 开发者
python类用法(四)
python类用法(四)
18 0