蓝桥杯省赛复盘(填空题)
第一次参加蓝桥杯,记录一下,并复盘
这是本人第一次参加蓝桥杯,当时从考场出来的时候,心是凉的,寻思着来年再战,结果居然得了个省二,可真是意料之外的惊喜。故写一篇文章记录一下当时比赛的感受,并分享一下赛后复盘的结果,由于能力有限,就先复盘一下填空。
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这都是我们的目标。愿我们一起加油
**附记:**最后一题有一部分代码是从网上找的,但是已经找不到链接,所以就没有附上原作了,还请谅解。