蓝桥杯刷题总结----第四周

一.夺宝奇兵

在一座山上,有很多很多珠宝,它们散落在山底通往山顶的每条道路上,不同道路上的珠宝的数目也各不相同.下图为一张藏宝地图:
7
3  8
8  1  0
2  7  4  4
4  5  2  6  5
”夺宝奇兵”从山下出发,到达山顶,如何选路才能得到最多的珠宝呢?在上图所示例子中,按照5-> 7-> 8-> 3-> 7的顺序,将得到最大值30

思路:简单的动态规划

n=eval(input())
G=[]
for _ in range(n):
    G.append(list(map(eval,input().split())))
dp=[[0 for i in range(n)] for j in range(n)]
for i in range(n):
    dp[0][i]=G[0][0]
for i in range(1,n):
    for j in range(n):
        if j>=len(G[i]):
            break
        else:
            if j==0:
                dp[i][j]=G[i][j]+dp[i-1][j]
            else:
                dp[i][j]=max(dp[i-1][j-1],dp[i-1][j])+G[i][j]
print(max([dp[n-1][j] for j in range(n)]))

二.实数相加

两行字符串,每行都是一个合法的实数。合法的意思是指:  整数部分的值如果大于零,则最高位数字必定大于零.  如果整数部分的值为零,则整数部分只有一个零.  小数部分尾部可以有任意多的零.  可以没有小数部分,  此时也没有小数点.  如果有小数点,  则至少需要有一位小数部分,  且允许是零. 

输入的实数满足如下要求:  (1)  小数点前的整数部分最多100位,(2)  小数点后的小数部分最多100位

思路:利用python的decimal保存小数,我使用字符串计算时会出现各种各样的错误

from decimal import *
getcontext().prec=1000
a=Decimal(input().strip())
b=Decimal(input().strip())
print(a+b)

 三.开灯游戏

有9盏灯与9个开关,编号都是1~9。
每个开关能控制若干盏灯,按下一次会改变其控制的灯的状态(亮的变成不亮,不亮变成亮的)。
具体如下:
第一个开关控制第二,第四盏灯;
第二个开关控制第一,第三,第五盏灯;
第三个开关控制第二,第六盏灯;
第四个开关控制第一,第五,第七盏灯;
第五个开关控制第二,第四,第六,第八盏灯;
第六个开关控制第三,第五,第九盏灯;
第七个开关控制第四,第八盏灯;
第八个开关控制第五,第七,第九盏灯;
第九个开关控制第六,第八盏灯。
开始时所有灯都是熄灭的,开关是关闭着的。要求按下若干开关后,使得只有4盏灯亮着。

思路:利用kaiguan列表保存控制的开关数,再dfs回溯

state=[1,0,0,0,0,0,0,0,0,0]
kaiguan=[[2,4],[1,3,5],[2,6],[1,5,7],[2,4,6,8],[3,5,9],[4,8],[5,7,9],[6,8]]
ans=[]
def dfs(s):
    global ans,state,kaiguan
    if len(s)==9:
        if sum(state)==5:
            ans.append(s)
           # print(state)
        return
    else:
        dfs(s+'0')
        for i in kaiguan[len(s)]:
            state[i]=(state[i]+1)%2
        dfs(s+'1')
        for i in kaiguan[len(s)]:
            state[i]=(state[i]+1)%2

dfs('')
for i in ans:
    print(i)

四.师座操作系统

师座这天在程序设计课上学了指针和结构体以后,觉得自己可以轻松的写出操作系统,为了打败大微软帝国,他给这个系统起了个响亮的名字“师座操作系统”,你是师座手下的首席架构师,被要求写这个操作系统的文件系统部分,要求如下:
这个文件系统有的所有文件都有一个独一无二的文件名,除此之外分为两类文件,一类文件是数据存储文件,它可以存储一个字符串信息,另一类文件是快捷方式,它会指向另一个文件,有可能是数据块也有可能是快捷方式。
.这个文件系统支持3条命令:
1.创建命令:create  < FileName>   < FileType>   < FileInfo>
这个命令的意思是,创建一个文件名为< FileName> ,文件类型为< FileType> ,文件信息  为< FileInfo> ,文件类型为0或者1,0表示数据块,1表示快捷方式,如果是数据块,那么< FileInfo> 表示储存  的字符串,如果这是一个快捷方式,< FileInfo> 表示指向的文件的名称,如果当前已存在名为< FileName> 的文件,  则更新这个文件的信息。
.2.打开命令:open  < FileName>
这个命令是打开文件名为< FileName> 的文件,如果这是一个快捷方式,则会打开这个快捷方式指向的文件,直到打开一个数据块时,显示这个数据块储存的信息并换行。
.3.退出命令:exit
得到这个命令以后,你的程序需要安全终止。

file_dic=dict()
while True:
    order=list(input().split())
    if order[0]=='exit':
        break
    elif order[0]=='create':
        if order[2]=='0':
            file_dic[order[1]]=[order[3],0]
        else:
            file_dic[order[1]]=[order[3],1]
    else:
        while file_dic[order[1]][1]!=0:
            order[1]=file_dic[order[1]][0]
        print(file_dic[order[1]][0])

五.打水问题

N个人要打水,有M个水龙头,第i个人打水所需时间为Ti,请安排一个合理的方案使得所有人的等待时间之和尽量小。
提示
一种最佳打水方案是,将N个人按照Ti从小到大的顺序依次分配到M个龙头打水。
例如样例中,Ti从小到大排序为1,2,3,4,5,6,7,将他们依次分配到3个龙头,则去龙头一打水的为1,4,7;去龙头二打水的为2,5;去第三个龙头打水的为3,6。
第一个龙头打水的人总等待时间  =  0  +  1  +  (1  +  4)  =  6
第二个龙头打水的人总等待时间  =  0  +  2  =  2
第三个龙头打水的人总等待时间  =  0  +  3  =  3
所以总的等待时间  =  6  +  2  +  3  =  11

思路:按顺序排好分组,让时间最短的先打,再求前缀和

n,m=map(eval,input().split())
t=list(map(eval,input().split()))
t.sort()
group=[[] for _ in  range(m)]
for i in range(n):
    group[i%m].append(t[i])
ans=0
for g in group:
    temp_sum=0
    for i in range(len(g)-1):
        temp_sum+=g[i]
        ans+=temp_sum
print(ans)

六.最小乘积

给两组数,各n个。
请调整每组数的排列顺序,使得两组数据相同下标元素对应相乘,然后相加的和最小。要求程序输出这个最小值。
例如两组数分别为:1  3  -5和-2  4  1
那么对应乘积取和的最小值应为:
(-5)  *  4  +  3  *  (-2)  +  1  *  1  =  -25

n=eval(input())
for _ in range(n):
    l=eval(input())
    num1=list(map(eval,input().split()))
    num2 = list(map(eval, input().split()))
    num1.sort()
    num2.sort(reverse=True)
    ans=0
    for i in range(l):
        ans+=num1[i]*num2[i]
    print(ans)

七.数的划分

一个正整数可以划分为多个正整数的和,比如n=3时:
3;1+2;1+1+1;
共有三种划分方法。
给出一个正整数,问有多少种划分方法。

思路:类比球放入盒子的排列组合,每个盒子不空,dp[i][j]表示i个球放入j个盒子,可以分为两种情况,每个盒子至少有两个球和最少有一个盒子只有一个球,所以dp[i][j]=dp[i-j][j]+dp[i-1][j-1]

n=eval(input())
dp=[[0 for _ in range(n)] for __ in range(n)]
for i in range(n):
    dp[i][0]=1
    dp[i][i]=1
for i in range(2,n):#i个球放入j个盒子 注意下标与实际问题的关系,要适当加一,以免出错
    for j in range(1,i):
        dp[i][j]=dp[i-j-1][j]+dp[i-1][j-1]#注意最后要减一 i-j-1
print(sum(dp[n-1]))

八.摆花

小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆。通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号。为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列。
试编程计算,一共有多少种不同的摆花方案。

样例说明:有2种摆花的方案,分别是(1,1,1,2),  (1,1,2,2)。括号里的1和2表示两种花,比如第一个方案是前三个位置摆第一种花,第四个位置摆第二种花。

思路:使用动态规划dp[i][j]表示当前用了i种花,用了j盆,遍历所有可能的情况
 

n,m=map(eval,input().split())
nums=list(map(eval,input().split()))
dp=[[0 for i in range(m+1)] for j in range(n+1)]
for i in range(1,nums[0]+1):
    dp[1][i]=1
for i in range(n+1):
    dp[i][0]=1
for i in range(2,n+1):
    for j in range(1,m+1):
        for k in range(nums[i-1]+1):
            if j<k:
                continue
            dp[i][j]+=dp[i-1][j-k]
print(dp[n][m]%1000007)

九.埃式筛法求素数

给定区间[L,  R]  ,  请计算区间中素数的个数。

from math import *
n,m=map(eval,input().split())
ans=[True for i in range(1000001)]
a=[True for i in range(1000001)]
a[1]=False
i=2
while i*i<=m:
    if a[i]:
        j=2
        while i*j<sqrt(m):
            a[i*j]=False
            j+=1
        k=ceil(n/i)
        while k*i<=m:
            if k!=1:
                ans[k*i-n]=False
            k+=1
    i+=1
ans=ans[:m-n+1]
print(ans.count(True))

十.排列式

7254是一个不寻常的数,因为它可以表示为7254  =  39  x  186,这个式子中1~9每个数字正好出现一次
输出所有这样的不同的式子(乘数交换被认为是相同的式子)
结果小的先输出;结果相同的,较小的乘数较小的先输出。

思路:暴力遍历两个乘数,求出乘积后利用集合分别判断三个数是否满足要求

def already_have(num,num_set):
    while num:
        if num%10 in num_set or num%10==0:
            return False
        else:
            num_set.add(num%10)
            num//=10
    return True
ans=[]
for i in range(2,99):
    for j in range(111,4999):
        if i*j<1000:
            continue
        else:
            set_num=set()
            if already_have(i,set_num) and already_have(j,set_num) and already_have(i*j,set_num) and len(set_num)==9:
                ans.append([i*j,i,j])
ans.sort(key=lambda x:x[0])
for i in ans:
    print("{} = {} x {}".format(i[0],i[1],i[2]))

十一.棋盘多项式

八皇后问题是在棋  盘上放皇后,互相不攻击,求方案。变换一下棋子,还可以有八车问题,八马问题,八兵问题,八王问题,注意别念反。在这道题里,棋子换成车,同时棋盘也得  换,确切说,是进行一些改造。比如现在有一张n*n的棋盘,我们在一些格子上抠几个洞,这些洞自然不能放棋子了,会漏下去的。另外,一个车本来能攻击和它  的同行同列。现在,你想想,在攻击的过程中如果踩到一个洞,便会自取灭亡。故,车的攻击范围止于洞。
此题,给你棋盘的规模n,以及挖洞情况,求放k个车的方案数(k从0到最多可放车数)

思路:利用邻接矩阵的不同值代表不同状态,0表示阻挡,1表示空位,2表示受到其他皇后的影响而不能放置,其中2可以叠加到4,这样回溯直接减2就可以恢复原来的状态
 

n=eval(input())
G=[]
for _ in range(n):
    G.append(list(map(eval,input().split())))
ans=[0 for _ in range(64)]
def dfs(i,j,num):
    global n,ans,G
    ans[num-1]+=1
    G[i][j]=2
    temp_i=n
    temp_j=n
    for ii in range(i+1,n):
        if G[ii][j]==0:
            temp_i=ii
            break
        G[ii][j]+=2
    for jj in range(j+1,n):
        if G[i][jj]==0:
            temp_j=jj
            break
        G[i][jj]+=2
    for ii in range(i,n):
        for jj in range(n):
            if ii==i and jj<=j:
                continue
            if G[ii][jj]==1:
                dfs(ii,jj,num+1)
    G[i][j]=1
    for ii in range(i+1,temp_i):
        G[ii][j]-=2
    for jj in range(j+1,temp_j):
        G[i][jj]-=2
    return
for i in range(n):
    for j in range(n):
        if G[i][j]==1:
            dfs(i,j,1)
for i in ans:
    if i==0:
        break
    print(i)

十二.洗牌

小弱T在闲暇的时候会和室友打扑克,输的人就要负责洗牌。虽然小弱T不怎么会洗牌,但是他却总是输。
渐渐地小弱T发现了一个规律:只要自己洗牌,自己就一定会输。所以小弱T认为自己洗牌不够均匀,就独创了一种小弱洗牌法。
小弱洗牌法是这样做的:先用传统洗牌法将52张扑克牌(1到K各四张,除去大小王)打乱,放成一堆,然后每次从牌堆顶层拿一张牌。如果这张牌的大小是  P(1到K的大小分别为1到13),那么就把这张牌插入到当前手中第P张牌的后面。如果当前手中不足P张牌,那么就把这张牌放在最后。
现在给你一对已经被打乱的牌,请你用小弱洗牌法进行洗牌,然后输出最后生成的序列。
注意:小弱可能在第一次洗牌时弄丢了某些牌,这时请你输出一个-1来提醒他牌的数目不够。

思路:简单的模拟

pai=[]
while True:
    try:
        nums=list(input().split())
        pai.append(nums)
    except:
        break
dui=[]
for i in range(len(pai)):
    for j in range(len(pai[i])):
        dui.append(pai[i][j])
if len(dui)<52:
    print(-1)
else:
    dic_num=dict()
    dic_num['1']=1
    dic_num['2']=2
    dic_num['3'] = 3
    dic_num['4'] = 4
    dic_num['5'] = 5
    dic_num['6'] = 6
    dic_num['7'] = 7
    dic_num['8'] = 8
    dic_num['9'] = 9
    dic_num['10'] = 10
    dic_num['J'] = 11
    dic_num['Q'] = 12
    dic_num['K'] = 13
    ans=[]
    for i in dui:
        if dic_num[i]>len(ans):
            ans.append(i)
        else:
            ans.insert(dic_num[i],i)
    for i in ans:
        print(i,end=' ')
    print()

十三.现代诗如蚯蚓

现代诗如蚯蚓
断成好几截都不会死
字符串断成好几截
有可能完全一样
请编写程序
输入字符串
输出该字符串最多能断成多少截完全一样的子串

样例说明
最多能断成四个”abc”,也就是abc重复四遍便是原串
同时也能断成两个”abcabc”
最坏情况是断成一个原串”abcabcabcabc” 

思路:直接从头开始遍历,求最小的长度

n=input()
num=len(n)
flag=True
for i in range(1,num//2+1):
    if n[:i]*(num//i) == n:
        print(num//i)
        flag=False
        break
if flag:
    print(1)

十四.种树

A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。园林部门  得到指令后,初步规划出n个种树的位置,顺时针编号1到n。并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度。但由于A城市土壤  肥力欠佳,两棵树决不能种在相邻的位置(i号位置和i+1号位置叫相邻位置。值得注意的是1号和n号也算相邻位置!)。

最终市政府给园林部门提供了m棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大。如果无法将m棵树苗全部种上,给出无解信息。

思路:注意是环形的,利用flag记录第一个节点是否种树

n,m=map(eval,input().split())
nums=list(map(eval,input().split()))
ans=-float('inf')
def dfs(i,temp_ans,temp_m,flag):
    global n,m,ans,nums
    temp_ans+=nums[i]
    if temp_m==m:
        if temp_ans>ans:
            ans=temp_ans

    else:
        if i+2<n:
            for ii in range(i+2,n):
                if ii ==n-1 and flag:
                    break
                dfs(ii,temp_ans,temp_m+1,flag)
for i in range(n):
    if i==0:
        dfs(i,0,1,True)
    else:
        dfs(i,0,1,False)
if ans !=-float('inf'):
    print(ans)
else:
    print('Error!')

十五.线段和点

有n个点和m个区间,点和区间的端点全部是整数,对于点a和区间[b,c],若a> =b且a< =c,称点a满足区间[b,c]。
求最小的点的子集,使得所有区间都被满足。

n, m = map(eval, input().split())
A = []
for i in range(n):
    A.append(eval(input()))
A.sort()  # A点集排序
B = []
for i in range(m):
    B.append(list(map(int, input().split())))
B = sorted(B, key=lambda x: (x[0], -x[1]))  # B区间排序
start = 0  # 定位推进区间
ans = 0
while start < m:
    max_num = 0
    max_index = 0
    for i in range(len(A)):  # 寻找使得start最接近m的点
        temp = start
        while temp < m:
            if B[temp][0] <= A[i] <= B[temp][1]:
                    temp = temp + 1
            else:
                break
        if temp > max_num:  # 记录该点的下标和区间
            max_num = temp
            max_index = i
    start = max_num  # 更新start
    del (A[max_index])  # 删除该点
    ans = ans + 1
    if len(A) == 0:
        break
if start == m:
    print(ans)
else:
    print(-1)

十六.超级玛丽

大家都知道" 超级玛丽" 是一个很善于跳跃的探险家,他的拿手好戏是跳跃,但它一次只能向前跳一步或两步。有一次,他要经过一条长为n的羊肠小道,小道中有m个陷阱,这些陷阱都位于整数位置,分别是a1,a2,....am,陷入其中则必死无疑。显然,如果有两个挨着的陷阱,则玛丽是无论如何也跳过不去的。
现在给出小道的长度n,陷阱的个数及位置。求出玛丽从位置1开始,有多少种跳跃方法能到达胜利的彼岸(到达位置n)。

思路:类似于爬楼梯

n,m=map(eval,input().split())
trap=set(map(eval,input().split()))
dp=[1 for i in range(n)]
for i in range(m):
    j=trap.pop()
    if j<=n:
        dp[j-1]=0
for i in range(2,n):
    if dp[i]==0:
        continue
    else:
        dp[i]=dp[i-1]+dp[i-2]
print(dp[n-1])

十七.质数的后代

在上一季里,曾提到过质数的孤独,其实从另一个角度看,无情隔膜它们的合数全是质数的后代,因为合数可以由质数相乘结合而得。
如果一个合数由两个质数相乘而得,那么我们就叫它是质数们的直接后代。现在,给你一系列自然数,判断它们是否是质数的直接后代。

思路:根据数据范围先求出所有的质数,再逐个判断

T=eval(input())
def is_prime(num):
    if num==2:
        return True
    else:
        for i in range(2,int(num**0.5)+1):
            if num%i==0:
                return False
    return True
prime_list=[]
for i in range(2,100000):
    if is_prime(i):
        prime_list.append(i)
def is_son(num):
    global prime_list
    if num%2==0:
        if is_prime(num//2):
            return True
        return False
    elif num==1:
        return False
    else:
        for i in prime_list:
            if i>num:
                break
            elif num%i==0 and num//i in prime_list:
                return True
        return False
for _ in range(T):
    if is_son(eval(input())):
        print("Yes")
    else:
        print("No")

十八.铺地毯

为了准备一个学生节,组织者在会场的一片矩形区域(可看做是平面直角坐标
系的第一象限)铺上一些矩形地毯。一共有n  张地毯,编号从1  到n。现在将这些地毯按照
编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上。
地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的编号。注意:在矩形
地毯边界和四个顶点上的点也算被地毯覆盖。
 

num=eval(input())
capmap=[]
for _ in range(num):
    capmap.append(list(map(eval,input().split())))
loc=list(map(eval,input().split()))
flag=False
for i in range(num-1,-1,-1):
    if capmap[i][0]<=loc[0] and capmap[i][0]+capmap[i][2]>=loc[0]:
        if capmap[i][1]<=loc[1] and capmap[i][1]+capmap[i][3]>=loc[1]:
            print(i+1)
            flag=True
            break
if not flag:
print(-1)

十九.项链

由  n(1≤n≤100)  个珠子组成的一个项链,珠子有红、蓝、白三种颜色,各种颜色的珠子的安排顺序由键盘输入的字符串任意给定。蓝色用小写字母b表示,红色用小写字母r表示,  白色用小写字母w表示.
假定从项链的某处将其剪断,把它摆成一条直线。先从左端向右收集同色珠子,遇到第一个异色珠子时停止.  收集过程中,  白色是一种特殊颜色,  既可以看成红色也可以看成蓝色。然后再从剩余珠子的右端向左重复上述过程。
例如:对下图一所示的项链,  如果从图一中标记的位置0处剪断,  则按顺时针顺序得到wbbbwwrrbwbrrwb(如图二所示)。这时从左端开始收集可以得到wbbbww,    共6个珠子;然后从剩余珠子右端开始收集得到wb,共2个珠子。这种剪法共可收集到6+2=8个珠子。  如果从图一中标记的位置4处剪断,  则按顺时针顺序得到wwrrbwbrrwbwbbb(如图二所示)。这时从左端收集可以得到wwrr,共4个珠子;  然后从剩余珠子右端收集可以得到wbwbbb,共6个珠子。这种剪法共可收集到4+6=10个珠子。
要求:  在项链中选择合适的剪断位置,  使得从左右两端收集到的珠子数目之和最大,输出收集到的珠子数的最大值M。

思路:从两边直接判断

string=input().strip()
ans=0

for i in range(len(string)):
    temp=0
    temp_i=0
    j=i
    while True:
        if string[j]=='b':
            if temp_i==0:
                temp_i=1
            elif temp_i==2:
                break
        elif string[j]=='r':
            if temp_i==0:
                temp_i=2
            elif temp_i==1:
                break
        temp+=1
        j=(j+1)%len(string)
    j=(i-1)%len(string)
    temp_i=0
    while True:
        if string[j]=='b':
            if temp_i==0:
                temp_i=1
            elif temp_i==2:
                break
        elif string[j]=='r':
            if temp_i==0:
                temp_i=2
            elif temp_i==1:
                break
        temp+=1
        j=(j-1)%len(string)
    if temp>ans:
        ans=temp
        ii=i
print(ans)

二十.密码锁

你获得了一个据说是古代玛雅人制作的箱子。你非常想打开箱子看看里面有什么东西,但是不幸的是,正如所有故事里一样,神秘的箱子出现的时候总是会挂着神秘的锁。
这个锁上面看起来有  N  个数字,它们排成一排,并且每个数字都在  0  到  2  之间。你发现你可以通过锁上的机关来交换相邻两个数字的顺序。比如,如果原来有  5  个数字  02120,在一次交换以后你就可以得到  20120,01220,02210  或者  02102。
根据你所搜集的情报,这个锁在上面存在某连续四个数字是“2012”的时候会自动打开。现在,你需要计算一下,你至少需要进行多少次交换操作才能打开这把锁?
对样例的解释
把前两个数字交换以后,锁上的数字是  20120,其中存在连续四个数字2,  0,  1,  2,因此锁会打开。

思路:简单的bfs

from collections import *
n=eval(input())
string=input()
q=deque()
q.append([string,0,-1])
if string.count('1')<1 or string.count('2')<2 or string.count('0')<1:
    print(-1)
else:
    num_dict=defaultdict(int)
    while len(q):
        temp_string, step, index = q.popleft()
        if '2012' in temp_string:
            print(step)
            break
        for i in range(n - 1):
            if i == index:
                continue
            else:
                my_temp_string = temp_string[:i] + temp_string[i + 1] + temp_string[i] + temp_string[i + 2:]
                if num_dict[my_temp_string]==0:
                    num_dict[my_temp_string]=1
                    q.append([my_temp_string, step + 1, i])

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值