蓝桥杯省赛复盘(2021填空)

蓝桥杯省赛复盘(填空题)

第一次参加蓝桥杯,记录一下,并复盘

这是本人第一次参加蓝桥杯,当时从考场出来的时候,心是凉的,寻思着来年再战,结果居然得了个省二,可真是意料之外的惊喜。故写一篇文章记录一下当时比赛的感受,并分享一下赛后复盘的结果,由于能力有限,就先复盘一下填空。

A.卡片
这是我唯一在考场上做并做对的一道填空十分简单
思路并不复杂,一开始并不知道结果的范围,但大概加估计,应该在一万以内,同时由于不论百位或者千位,都是“1”开始,所以盲猜“1”应该会先用完,由此写出了代码,最后结果也证明我是对的

#卡片
count = 0     #初始值
for i in range(10000):
    for k in str(i):
        if k == "1":   #判断包含“1”的数
            count += 1
            if count == 2021:
                print(i)

B.直线
其实这道题思路并不复杂,我们都知道直线可以表示为y=ax+b的形似,所以,只要判断出 a,b 两个数就行,组成[a,b]将其放在一个二维列表里面,并进行判断就可以了,但是考试时脑子抽抽,就可着a较劲,浪费了大半时间,等想起来还有一个b的时候,又忘记了求b的公式,最后无奈,只好放弃。现在想想,初中的知识还是有用的,不要一上了大学就什么都忘了
#直线

#直线
list_1,list_2,list_3,list_4= [],[],[],[]    #初始化几个列表,用来存储不同的值
count = 0       #初始化结果值
for x in range(0,20):
    for y in range(0,21):
        x_y = [x,y]        #确定题目中的坐标
        list_1.append(x_y)      #将所有坐标存储在一个二维列表中
for a in list_1:
    for b in list_1:
        if a[1]==b[1]:    #即y相等
            if a[1] not in list_2:   #y相等是一条a=0直线,所以将其存储进一个列表,并count+1,然后后面要是再出现相同的y就可以不管了,应为都在一条直线上
                list_2.append(a[1])
                count += 1
            else:
                continue
        elif a[0]==b[0]:      #即x相等
            if a[0] not in list_3:   #x相等是一条没有斜率的直线,理由同上
                list_3.append(a[0])
                count += 1
            else:
                continue
        else:
            k = (a[1]-b[1])/(a[0]-b[0])    #即a
            c = (a[0]*b[1]-a[1]*b[0])/(a[0]-b[0])   #b = (x1y2-x2y1)/(x1-x2)
            l = [k,c]   #两个特征值求出,然后将其存储进一个列表
            if l not in list_4:  #防止出现相同特征值
                list_4.append(l)
                count += 1
            else:
                continue
print(count)

C.货物摆放
这道题相信大家一开始都是会的,毕竟循环谁不知道了,而我很有幸,也是这循环大军的一员,当然,结果嘛…我想各位也知道,就不那么幸运了。于是下来我又想了很久,后来,还是在网上看见某大佬的代码,才明白是怎么回事

#货物摆放
import math
def func(num):
    list_1 = []
    for i in range(1, int(math.sqrt(num))+1):  #循环到num的二次根号,因为通过除法就可以找到所有的相乘得num的整数,并将其存储在列表中
        if num % i == 0:
            list_1.append(i)
            list_1.append(num // i)
    return list_1
count = 0
n = eval(input())
list_1 = func(n)   #上面将num拆分为了两两相乘,也就是num的所有因数
for l in list_1:
    for w in list_1:
        for h in list_1:
            if l * w * h == n:  #将所有因数可能相乘即可,其中的数学原理我也不是很懂,毕竟我还想着把l,m,h进行再拆分,但最后结果就是这样。
                count += 1
print(count)

其实这道题的关键就是那个求num的二次根号,这就将本来的16位数化成了8位(应该是,本来看过一次,但是忘了,这里又不想转头再去看)数,大大降低了循环的级数,当然,这本身也是一个极大的循环了

D.路径
这是一个图的问题,十分有意思,我记得在比赛前我做过2020年的一道真题叫”网络流裸题“,虽然形式不一样,但是用到的思想是一直的,都是”最短路径“的思想,不过那是一道编程题,虽然得出了结果,但是却超出了时间,我也是十分无奈。对于这个,有两种方法解决,即迪杰斯特拉算法和弗洛伊德算法,当然,两相比较,弗洛伊德要简单许多,可是由于我做上一道题的时候用的是迪杰斯特拉,直接把代码就ctrl+c ctrl+v了

#路径
import math
dict1 = {}    #由于这是一个加权图的问题,就用字典,它可以形象的表示每一个点与哪几个点连接,并且用key表示与它连接的点,key后面的value就表示权
def gcd(m,n):   #这是一个求最大公约数的函数,放心,我没有失心疯,还记得是求最小公倍数
    m,n = int(m),int(n)
    s = math.gcd(m,n)
    return s

for i in range(1,2022):
    dict1[i] = {}
    for r in range(i,i+22):
        if r <= 2021:
            dict1[i][r] = int(i*r/gcd(i,r))   #dict的key不用提前确定,可以临时赋名,十分方便
        else:
            continue
    dict1[i][i] = 0  #有兴趣的可以print一下看看,当然,我用的2021,太大了,可以改小了再看

def Dijkstra(G, v0, INF=999999999999999):   #重头戏来了!!!
    book = set()
    minv = v0

    dis = dict((k, INF) for k in G.keys())
    dis[v0] = 0

    while len(book) < len(G):
        book.add(minv)
        for w in G[minv]:
            if dis[minv] + G[minv][w] < dis[w]:   #寻找最小
                dis[w] = dis[minv] + G[minv][w]

        new = INF
        for v in dis.keys():
            if v in book: continue  book的作用与第三题的几个list一样,防止重复
            if dis[v] < new:
                new = dis[v]  #锲而不舍地找最小
                minv = v
    return dis


dis = Dijkstra(dict1, v0=1)
print(max(dis.values()))  #dis.value里面存储的是经历过每一个点的值,所有要找最大的

对于算法我也不是特别明了,给反正当时就这样写了,所以讲得也不好

E.回路计数
其实与上一道题类似,不过上一道是加权图的话,这一道就是非加权的,只要知道有路径就可以了,路径长短都无所谓,所以我们第一步就是确定各点与哪些点相连,第二步就是用DP寻找路径,网上的大佬说要用状压DP咱也不知道是啥,就写了给普通DP

#回路计数
def hz(m,n):    #寻找互质数
    if m == 1:
        return False
    if n==1:
        return False
    elif m%n!=0 and n%m!=0:
        return False
    else:
        return True

list_1 = [[]for _ in range(21)]
dict1 = {}  #上面说了,“图”的问题,用dict
#当然,这次是非加权,所以用了,在最外层代表代表点(key),但在里面,即对应value用的是list,毕竟不用加权,表示与key相连的点就可以了,这次是用了,但没完全用
for i in range(1,22):
    dict1[i] = []
    for r in range(1,22):
        if hz(i,r) == False:
            list_1[i-1].append(r)
            dict1[i].append(r)
del list_1[0][0]
del dict1[1][0]   #由于点1不能和点1连接,所以删除

for i in range(1,22):   #因为数字太多,容易弄混淆,所以将点转化成字母的形式
    dict1[chr(i+96)] = dict1.pop(i)
    for r in range(len(dict1[chr(i+96)])):
        dict1[chr(i+96)][r] = chr(dict1[chr(i+96)][r]+96)
print(dict1)  #看看结果形式

def searchGraph(graph, start, end):   #重头戏,但是从书上剽,在网上窃,东拼西凑,也不是很懂,就别指望我讲清楚了
    results = []
    generatePath(graph, [start], end, results)
    results.sort(key=lambda x:len(x))
    return results

def generatePath(graph, path, end, results):
    state = path[-1]
    if state == end:
        results.append(path)
    else:
        for arc in graph[state]:
            if arc not in path:
                generatePath(graph, path + [arc], end, results)

count = 0
Graph = dict1
r = searchGraph(Graph, "a","u")
print('     path a to u:')
for i in r:
    count += 1
print(count)   #前面说了,大佬说的用状压DP,而我是普通的,结果就是
"memoryerror"即内存使用超过2G,超出电脑运行范围,同时让我跑爆了IDLE,Pycharm,Jupter Notebook,也是心伤

做这道题的时候比较闲,就多事,将题中描述的图画了出来,代码附在下面,感兴趣的朋友可以自己跑跑试试。

# 矩阵生成图
import networkx as nx
import matplotlib.pyplot as plt
import numpy as np

G = nx.Graph()
Matrix = np.array(list_2)
for i in range(len(Matrix)):
    for j in range(len(Matrix)):
        G.add_edge(i, j)

nx.draw(G)
plt.show()
#如上所有列表和上面一直,复制上去就直接能出结果

写在最后
其实比赛也好,学习算法也好,都是一个艰难的过程,在其中,我们会遇见困难,但只要我们有克服困难的决心,就能慢慢的进步,蓝桥杯只是我们比赛生涯中一个过客罢了,往后还有国赛,程序设计赛,乃至于ACM-ICPC这都是我们的目标。愿我们一起加油
**附记:**最后一题有一部分代码是从网上找的,但是已经找不到链接,所以就没有附上原作了,还请谅解。

  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值