不忘初心,
牢记使命。

第十一届蓝桥杯python组试题解答

2021-04-09 大聪明 0评论 690 0喜欢

第十一届蓝桥杯python组试题解答

门牌制作

在这里插入图片描述

这道题目的意思是,找到[1, 2020] (注意是闭区间) 之间所有的数中包含2的数中2的个数的中枢。
也就是说从1开始找,找到含有2的数的,然后看这个数中有几个2。

例如2021就贡献了两个2.

方法一:数位分离

count = 0

for i in range(1, 2021):
    n = i
    while n != 0:
        m = n % 10
        n = n // 10
        if m == 2:
            count += 1

print(count)
# 624

方法二:强转字符串

count = 0

for i in range(1, 2021):
    count += str(i).count('2')

print(count)
# 624

寻找2020

在这里插入图片描述

数据是给的一个txt文件,里边有300行300列的数据,全部是数字0和数字2。我在官网上和其他地方也没有找到这个txt文件,就用样例数据测试吧。

220000
000000
002202
000000
000022
002020

注意:从文件里读出来的数据全部是字符串。

def check_s(s):
    return s == '2020'


data = []
# test.txt
# 220000
# 000000
# 002202
# 000000
# 000022
# 002020

# 读取数据
with open('test.txt', mode='r', encoding='utf-8') as fp:
    for line in fp:
        line = list(line.strip())
        data.append(line)

print(data)
# 读出来的全是字符串
# [['2', '2', '0', '0', '0', '0'], 
#  ['0', '0', '0', '0', '0', '0'], 
#  ['0', '0', '2', '2', '0', '2'], 
#  ['0', '0', '0', '0', '0', '0'], 
#  ['0', '0', '0', '0', '2', '2'], 
#  ['0', '0', '2', '0', '2', '0']]

m, n = len(data), len(data[0])
count = 0

for i in range(m):
    for j in range(n):
        # 行
        if i + 3 < n and check_s(data[i][j] + data[i+1][j] + data[i+2][j] + data[i+3][j]):
            count += 1
        # 列
        if j + 3 < m and check_s(data[i][j] + data[i][j+1] + data[i][j+2] + data[i][j+3]):
            count += 1
        # 斜
        if i + 3 < n and j + 3 < m and check_s(data[i][j] + data[i+1][j+1] + data[i+2][j+2] + data[i+3][j+3]):
            count += 1

print(count)
# 5

发散思维:考虑用字符串的count()函数来处理,每行每列的字符串很容易读出,然后用line.count('2020')就可一得出line这个字符串中有多少个字串‘2020’,但是斜着怎么把对应的字符串取出没有找到很好的办法,有时间再更新。各位有想出好办法的可评论区留言。

跑步锻炼

在这里插入图片描述

直接利用python的标准库datetime里的datetime timedelta weekday即可方便的求出。关键位置已经给出解析。

import datetime

distances = 0
start_time = datetime.datetime(year=2000, month=1, day=1)  # 2000年1月1日00:00 周六
dela = datetime.timedelta(days=1)
end_time = datetime.datetime(year=2020, month=10, day=1)  # 到2020年10月2日00:00 这样包括10月1号 周四
time = end_time - start_time  # time为一个timedelta对象
# start_time.weekday() 返回数字0-6,0代表星期一,依次类推  5 代表星期六

while start_time <= end_time:
    if start_time.day == 1 or start_time.weekday()  == 0:
        # 月初或周一
        distances += 2
    else:
        distances += 1
    start_time += dela

print(distances)  # 8879

蛇皮走位

在这里插入图片描述

推荐用手算,挺快的。用代码的话也不是不可以。最近挺忙的,我的个人小站http://47.116.137.43/即将上线,域名liboer.top在备案中暂时不能以域名访问,还没有做cdn加速,首次访问加载会略慢,到时欢迎大家来访。这里就提供一下手算方法,关于代码有时间再补,也欢迎大家在评论区补上。
解题思路
我们可以看到,数的个数累加是以n(n+1)/2的方式递增,只不过最终的那个数分奇偶次序:奇数列、偶数行。例如:3三列第一个数字为3(3+1)/2=6 第四行第一个数为4(4+1)/2=10。所以要求第20行20列的数我们要知道它是斜着数的第几个。我们可以看到他是左右对称的,所以第20列的右边还有(20-1)=19列 所以第39列的第一个数是20行20列那个数所在的斜着的最后一个数。39是奇数,所以39(39+1) /20=780 780还有减去多出来的(39-20)=19个数 所以最终结果为 780 - 19 = 761
我的解题步骤

在这里插入图片描述

排序

在这里插入图片描述

冒泡排序
条件:相邻交换 交换100次 只有小写字母 不重复 最短 字典序最小
首先,相邻交换、只有小写字母 、不重复 、最短可以初步判定直接逆序,因为这样最短的串可以交换最多的次数。很容易得知交换次数为n(n-1)/2,n=15时,全部逆序可交换105次
即:onmlkjihgfedcba,交换105次
现在要交换100次,所以这个o肯定要往右移,很容易想到nmlkjoihgfedcba,这样是100次
但是,再看条件:字典序最小,所以要尽可能把小的往左移,考虑到多了五次,我们就把第五个字母j放在最后,这样jonmlkihgfedcba,每次交换都少移动五次,最后到j时恢复到逆序。
例如:
jonmlkihgfedcba 就是把o放到最后,得到jnmlkihgfedcbao。相比onmlkjihgfedcbao放到最后少了一次,nmlkjihgfedcbao
jnmlkihgfedcbao 就是把n放到最后,得到jmlkihgfedcbano。相比nmlkjihgfedcbaon放到最后少了一次
......
jonmlkihgfedcbajihgfedcbaklmno正好少了五次, 五次后onmlkjihgfedcba也变成了jihgfedcbaklmno后边就都一样了
结果:jonmlkihgfedcba

代码解释

def bubbl_sort(alist, count):
    for i in range(len(alist) - 1):
        for j in range(len(alist) - 1 - i):
            if alist[j] > alist[j+1]:
                count += 1
                alist[j], alist[j+1] = alist[j+1], alist[j]
        print(alist)
    return (alist, count)

count = 0
print(bubbl_sort(list('jonmlkihgfedcba'), count))


# 每趟循环结果
['j', 'n', 'm', 'l', 'k', 'i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a', 'o']
['j', 'm', 'l', 'k', 'i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a', 'n', 'o']
['j', 'l', 'k', 'i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a', 'm', 'n', 'o']
['j', 'k', 'i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a', 'l', 'm', 'n', 'o']
['j', 'i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a', 'k', 'l', 'm', 'n', 'o']
['i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a', 'j', 'k', 'l', 'm', 'n', 'o']
['h', 'g', 'f', 'e', 'd', 'c', 'b', 'a', 'i', 'j', 'k', 'l', 'm', 'n', 'o']
['g', 'f', 'e', 'd', 'c', 'b', 'a', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o']
['f', 'e', 'd', 'c', 'b', 'a', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o']
['e', 'd', 'c', 'b', 'a', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o']
['d', 'c', 'b', 'a', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o']
['c', 'b', 'a', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o']
['b', 'a', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o']
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o']


(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'], 100)

成绩统计

在这里插入图片描述

在这里插入图片描述

这里首先说一下round函数

python中的round()在保留小数位数的时候采取的实际上不是四舍五入的原则 它采取的是一种相对更加公平的原则:
在四的情况下肯定是要舍掉了.主要是针对五的情况. 遇到5时,它认为是处于中间的, 此时到底是该舍弃还是进位呢.查询了一下网上说是和取舍的位数前的小数奇偶性有关,奇就舍偶就进.我认为这样也不全面.比如下边这个例子怎么说?
例如

print(round(1.675, 2))  # 1.68
print(round(2.675, 2))  # 2.67
print(round(3.675, 2))  # 3.67
print(round(4.675, 2))  # 4.67

但是还是想说一点,本题目直接用round还是有大概率满分的,因为像这种数据在本题中很难出现.
方法一:用round

n = int(input())
jige = good = 0
for i in range(n):
    s = int(input())
    if 60 <= s < 85:
        jige += 1
    elif s >= 85:
        good += 1

r1 = round((jige+good)/n, 2)
r2 = round(good/n, 2)

print(int(r1*100), '%', sep='')
print(int(r2*100), '%', sep='')

方法一:自定义进位

def round_2(s):
    s = str(s)
    if len(s) > 3:
        if int(s[3]) > 4:
            s = s[0] + str(int(s[1]) + 1)
        else:
            s = s[:2]
    return s


n = int(input())
jige = good = 0
for i in range(n):
    s = int(input())
    if 60 <= s < 85:
        jige += 1
    elif s >= 85:
        good += 1


r1 = round_2(((jige+good) / n) * 100)
r2 = round_2((good/n) * 100)

print(r1, '%', sep='')
print(r2, '%', sep='')

单词分析

在这里插入图片描述

在这里插入图片描述

搞一个列表,长度为26,记录每个字符出现的次数
遍历单词,每个字母的ASCII码值-97作为索引存入对应的arr
找出arr中最大的即为最多次数,有相同的无所谓
找最大值对应的索引,默认返回从左到右数第一个匹配的值的索引,此时即为字典序最小
对应的索引值+97即为对应的字符

代码

word = input()
arr = [0 for i in range(26)]

for alpha in word:
    arr[ord(alpha) - 97] += 1

num = max(arr)

alp = chr(arr.index(num)+97)

print(alp)
print(num)

数字三角形

在这里插入图片描述

在这里插入图片描述

条件理解

动态规划问题。此题比较坑的就是这个条件:
向左下走的次数与向右下走的次数相差不能超过1 条件1
其实我查阅资料曹发现它的意思是说向左下和向右下分别总共走的次数的差值不超过1就行。不是说时时刻刻都要保证差值不超过1.比如:
n = 5时,左下 左下 右下 右下 这样走就满足条件 因为总共走的左下2次 右下2次 2-2=0 < 1 满足
而不是说 先走左下 第二次就必须走右下 因为此时左下次数为1 右下次数为0 再走左下的话左下次数为2 右下次数为0 2-0=2>1就不满足了 所以第一步走左下 第二步就必须走右下 这样就是时时刻刻都要保证条件1了。
本人很不幸开始就读了条件1就以为要时刻保证条件1 怎么也做不出来 谁知只需总次数保证条件1即可 不知道题目没有表达清楚 还是我理解力有问题
例如n = 6时
左下 左下 左下 右下 右下 右下 这样走都满足他说的条件1

思路:

做一个dp数组记录所有最大值情况每一步走下来的最大值
最后找最后一行中间的值即为满足条件1的值

n = int(input())  # 输入的N

l = []  # 存储输入的值

for i in range(n):
    l.append(list(map(int, input().split())))  # 输入数据值

dp = [[0 for _ in range(n)] for _ in range(n)]
dp[0][0] = l[0][0]

for i in range(1, n):
    for j in range(i+1):
        if j == 0:
            dp[i][j] = l[i][j] + dp[i-1][j]
        elif j == i:
            dp[i][j] = l[i][j] + dp[i-1][j-1]
        else:
            dp[i][j] = max(dp[i-1][j-1], dp[i-1][j]) + l[i][j]

# 两边的无法保证条件1,只有中间的才能满足,
# 且如果n为奇数,肯定时中间的哪一个
# 如果n为偶数,则为中间两个之间最大的一个
if n % 2 == 0:
    print(max(dp[-1][n//2-1], dp[-1][n//2]))
else:
    print(dp[-1][n//2])

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

# print(dp)
# [
#     [7, 0, 0, 0, 0, 0], 
#     [10, 15, 0, 0, 0, 0], 
#     [18, 16, 15, 0, 0, 0], 
#     [20, 25, 20, 19, 0, 0], 
#     [24, 30, 27, 26, 24, 0], 
#     [25, 32, 33, 31, 31, 30]
# ]

平面切分

在这里插入图片描述

规律

在同一个平面内,如果添加的每一条直线互不相交,则每添加一条直线,就会增加一个平面;当添加一条直线时,这条直线与当前平面内已有直线每产生一个不同位置的交点时,这条直线对平面总数量的贡献会额外增多一个。
例如:
在平面上:
画一条直线 分成2个平面
再画一条直线
如果不产生交点 再之前的平面数上再加1
如果产生n个不同的交点 再之前的平面数上加 1+n

思路

建一个类,存放直线的A和B,表示每条直线
从第2条直线开始循环判断与它前边的所有直线的位置关系,记录下不重复的交点的个数。
最后累加个数再加上本身贡献量1

class Straight:
    def __init__(self, a, b):
        self.a = a
        self.b = b

def relation(line1, line2):
    if line1.a == line2.a:
        # 平行
        return
    # 不平行,求交点
    x = -(line1.b - line2.b) / (line1.a - line2.a)
    y = line1.a * x + line1.b
    point.add((x, y))



n = int(input())
line = []

for i in range(n):
    a, b = list(map(int, input().split()))
    line.append(Straight(a, b))
res = 0

if line:
    res = 2
    for i in range(1, len(line)):
        point = set()
        for j in range(i):
            relation(line[i], line[j])
        res += len(point) + 1

print(res)

装饰宝珠

在这里插入图片描述

在这里插入图片描述

粗略的看来一下应该挺麻烦,有时间仔细看看。最近还有其他事情,这题待解答。有会得网友评论区贴代码通知我补更。

发表评论 取消回复

电子邮件地址不会被公开。

请输入正确格式的qq邮箱
请输入以http或https开头的URL,格式如:https://libo_sober.top