蓝桥杯 Python算法-基础练习

基础练习

    • 杨辉三角形(二维数组)
    • 矩阵乘法
    • 完美的代价(回文串)
    • 芯片测试
    • 2n皇后问题(八皇后问题 DFS)
    • Huffuman树(贪心 Huffuman)
    • 阶乘(高精度阶乘 超时)

杨辉三角形(二维数组)

杨辉三角形又称Pascal三角形,它的第i+1行是(a+b)i的展开式的系数。  
它的一个重要性质是:三角形中的每个数字等于它两肩上的数字相加。
下面给出了杨辉三角形的前4行: 
1
1 1
1 2 1
1 3 3 1 
给出n,输出它的前n行。

输入格式:
  输入包含一个数n。
输出格式:
  输出杨辉三角形的前n行。每一行从这一行的第一个数开始依次输出,中间使用一个空格分隔。请不要在前面输出多余的空格。
  
样例输入
4
样例输出
1
1 1
1 2 1
1 3 3 1

#二维数组的创建方式:list1 = [ [] for i in range(n) ] 
#n行数组,每行为一个[]
n = int(input())
a = [[] for i in range(n)]
for i in range(n):
    for j in range(n):
        if j == 0 :
            a[i].append(1)
        elif (j<i and j !=0):
            a[i].append(a[i-1][j-1] + a[i-1][j]) 
        elif (j == i and j !=0):
            a[i].append(1)
            break
for i in range(n):
    for j in range(len(a[i])):
        if j != i:
            print(a[i][j],end=" ")
        elif j == i:
            print(a[i][j])

矩阵乘法

问题描述
  给定一个N阶矩阵A,输出A的M次幂(M是非负整数)
  例如:
  A =
  1 2
  3 4
  A的2次幂
  7 10
  15 22
输入格式
  第一行是一个正整数N、M(1<=N<=30, 0<=M<=5),表示矩阵A的阶数和要求的幂数
  接下来N行,每行N个绝对值不超过10的非负整数,描述矩阵A的值
输出格式
  输出共N行,每行N个整数,表示A的M次幂所对应的矩阵。相邻的数之间用一个空格隔开
  
样例输入
2 2
1 2
3 4
样例输出
7 10
15 22

import copy
n,m = map(int,input().split( ))
s=[]
for i in range(n):
    s.append(list(map(int,input().split( ))))
ans=[[0 for j in range(n)] for i in range(n)]  #n阶方阵存放结果
s1 = copy.deepcopy(s) #深拷贝

if m == 0: #矩阵的0次幂是单位矩阵E
    for a in range(n):
        ans[a][a] = 1
else:
    while(m>1): #n次幂
        for i in range(n):
            for j in range(n):
                number = 0
                for k in range(n):
                    number += s[i][k]*s1[k][j]
                ans[i][j] = number
        s1 = copy.deepcopy(ans) #s1变成新的乘后的矩阵,等待下一次乘
        m -= 1   
for i in range(n):
    for j in range(n):
         if j != (n-1):
            print(ans[i][j],end=" ")
         elif j == (n-1):
            print(ans[i][j])

完美的代价(回文串)

问题描述
  回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
  交换的定义是:交换两个相邻的字符
  例如mamad
  第一次交换 ad : mamda
  第二次交换 md : madma
  第三次交换 ma : madam (回文!完美!)
  
输入格式
  第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
  第二行是一个字符串,长度为N.只包含小写字母
输出格式
  如果可能,输出最少的交换次数。
  否则输出Impossible
  
样例输入
5
mamad
样例输出
3

string.count(str, beg=0, end=len(string)) :返回 str 在 string 里面出现的次数,如果 beg 或者 end 指定则返回指定范围内 str 出现的次数
string.index(str, beg=0, end=len(string)) 同上,但不存在会报错

#判断是否可以经过调整变成回文串
#字符串长度为偶数:每一个字母都出现偶数次
#长度为奇数: 只有一个字母的出现次数为奇数
def ishuiwen(s,n):
    temp = 0 #计数长度为奇数时,字母出现次数为奇数的个数
    if n %2 ==0: #长度为偶数
        for i in range(26): #遍历26个字母
            if s.count(chr(97+i)) % 2 != 0: #出现次数为奇数
                print("Impossible")
                return 0
        else:
            return 1
    else: #长度为奇数
        for j in range(26):
            if s.count(chr(97+j)) % 2 != 0: 
                temp +=1
            if temp >1:	#出现次数大于1
                print("Impossible")
                return 0
        else:
            return 1
#进行交换
def change(n,s,s1,res): #s1=s[::-1]
    for i in range(n//2): #遍历前一半
        if s[i:].count(s[i]) != 1: #第i个字符出现次数不为1
            temp = s1[:n-i].index(s[i]) #在逆序中找到另一个i字符的位置index
            s1.pop(temp) #在逆序中删除这个重复的字符
            res +=temp #这个重复的字符所在的index即为需要把它挪到和i对应位置的交换次数
            s = s1[::-1] #更新正序
        else: #出现次数=1
            res += n//2 - i	#只出现一次的字符距离中心(n//2)的距离【交换次数】
            s[i] = None #不能写成pop()因为这样后面的列表数会前移但i继续+1
            s1 = s[::-1] #更新逆序
    return res
if __name__ == "__main__":
    n = int(input()) #字符串长度
    s = list(input())
    s1 = s[::-1]
    res = 0
    if ishuiwen(s,n) == 1: #可以变成回文串
        res = change(n,s,s1,res)
        print(res)

芯片测试

问题描述
  有n(2≤n≤20)块芯片,有好有坏,已知好芯片比坏芯片多。
  每个芯片都能用来测试其他芯片。用好芯片测试其他芯片时,能正确给出被测试芯片是好还是坏。而用坏芯片测试其他芯片时,会随机给出好或是坏的测试结果(即此结果与被测试芯片实际的好坏无关)。
  给出所有芯片的测试结果,问哪些芯片是好芯片。
  
输入格式
  输入数据第一行为一个整数n,表示芯片个数。
  第二行到第n+1行为n*n的一张表,每行n个数据。表中的每个数据为0或1,在这n行中的第i行第j列(1≤i, j≤n)的数据表示用第i块芯片测试第j块芯片时得到的测试结果,1表示好,0表示坏,i=j时一律为1(并不表示该芯片对本身的测试结果。芯片不能对本身进行测试)。
输出格式
  按从小到大的顺序输出所有好芯片的编号
  
样例输入
3
1 0 1
0 1 0
1 0 1
样例输出
1 3

已知好芯片比坏芯片多
假如我们有100个待测芯片,其中51个好的,49个坏的,我现在拿到一个好的,剩下的50个好的会测出来50个1。
如果第i个芯片是好的,则第i行的所有matrix1[i][j]和 >= n/2
第i个芯片是好的→用i好芯片测试j芯片得到的好芯片(1)数量 >= n/2

n = int(input()) 
matrix1 = [[]*n for i in range(n)]
for i in range(n):
    matrix1[i] = list(map(int,input().split( )))
for i in range(n):
    cnt = 0
    for j in range(n):
        if matrix1[j][i] == 1:	#遍历矩阵一行
            cnt += 1
    if cnt >= (n/2) : #第i个芯片是好芯片
        if i != (n-1):
            print(i+1,end=' ')
        else:
            print(i+1)

2n皇后问题(八皇后问题 DFS)

问题描述
  给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
  
输入格式
  输入的第一行为一个整数n,表示棋盘的大小。
  接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出格式
  输出一个整数,表示总共有多少种放法。

样例输入
4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
0

n皇后问题 的拓展

n = int(input())#皇后数量
matr = [[]*n for i in range(n)] #储存棋盘
for i in range(n):
    matr[i] = list(map(int,input().split( )))
ans = 0 #方案数
temp_W = [None for x in range(n)]   #暂存白皇后
temp_B = [Non e for x in range(n)]   #暂存黑皇后

def valid_W(temp_W,row): #验证白皇后
    if matr[row][temp_W[row]] == 1: #可以落子
        for pre in range(row): #是否同列或同对角线
            if abs(row - pre) == abs(temp_W[row]-temp_W[pre]) or temp_W[pre] == temp_W[row]:
                return 0
        return 1
        
def valid_B(temp_B,row,temp_W): #验证黑皇后
    if matr[row][temp_B[row]] == 1 and temp_B[row] != temp_W[row]: #可以落子且不和白皇后重复
        for pre in range(row):
            if abs(row - pre) == abs(temp_B[row]-temp_B[pre]) or temp_B[pre] == temp_B[row]:
                return 0
        return 1
                    
def dfs_W(temp_W,row): #先对白皇后进行DFS
    if row == n: #白皇后n枚旗子落完,接下来该黑皇后
        dfs_B(temp_B,0)
    else:
        for col in range(n):
            temp_W[row] = col
            if valid_W(temp_W,row) == 1:
                dfs_W(temp_W,row+1)
                
def dfs_B(temp_B,row): #接着对黑皇后进行DFS
    if row == n: #黑皇后也落完n枚旗子
        ans += 1 #完成一种2n方案
        return
    else:
        for col in range(n):
            temp_B[row] = col
            if valid_B(temp_B,row,temp_W) == 1:
                dfs_B(temp_B,row+1)
dfs_W(temp_W,0)
print(ans)

Huffuman树(贪心 Huffuman)

问题描述

Huffman树在编码中有着广泛的应用。在这里,我们只关心Huffman树的构造过程。
  给出一列数{pi}={p0, p1, …, pn-1},用这列数构造Huffman树的过程如下:
  1. 找到{pi}中最小的两个数,设为pa和pb,将pa和pb从{pi}中删除掉,然后将它们的和加入到{pi}中。这个过程的费用记为pa + pb。
  2. 重复步骤1,直到{pi}中只剩下一个数。
  在上面的操作过程中,把所有的费用相加,就得到了构造Huffman树的总费用。
  本题任务:对于给定的一个数列,现在请你求出用该数列构造Huffman树的总费用。
  例如,对于数列{pi}={5, 3, 8, 2, 9},Huffman树的构造过程如下:
  1. 找到{5, 3, 8, 2, 9}中最小的两个数,分别是2和3,从{pi}中删除它们并将和5加入,得到{5, 8, 9, 5},费用为5。
  2. 找到{5, 8, 9, 5}中最小的两个数,分别是5和5,从{pi}中删除它们并将和10加入,得到{8, 9, 10},费用为10。
  3. 找到{8, 9, 10}中最小的两个数,分别是8和9,从{pi}中删除它们并将和17加入,得到{10, 17},费用为17。
  4. 找到{10, 17}中最小的两个数,分别是10和17,从{pi}中删除它们并将和27加入,得到{27},费用为27。
  5. 现在,数列中只剩下一个数27,构造过程结束,总费用为5+10+17+27=59。
  
输入格式
  输入的第一行包含一个正整数n(n<=100)。
  接下来是n个正整数,表示p0, p1, …, pn-1,每个数不超过1000。
输出格式
  输出用这些数构造Huffman树的总费用。
  
样例输入
5
5 3 8 2 9
样例输出
59

哈夫曼树(最优二叉树),构建思想:反复选择两个最小的元素,合并,直到只剩下一个元素

n = int(input()) #n个正整数
p =list(map(int,input().split( ))) #存为list列表
ans =[] #存放每一步的花费
while n > 1 :
    x1 = min(p) #最小数
    p.remove(x1) #移除最小数
    x2 = min(p) #当前最小数
    p.remove(x2) #移除
    x = x1+x2 	#将两个最小数合并
    ans.append(x) #记录该步花费
    p.append(x) #新合成的数加入列表
    n -=1  #个数-1
print(sum(ans)) #计算总花费

阶乘(高精度阶乘 超时)

问题描述
  输入一个正整数n,输出n!的值。
  其中n!=123*…*n。
算法描述
  n!可能很大,而计算机能表示的整数范围有限,需要使用高精度计算的方法。使用一个数组A来表示一个大整数a,A[0]表示a的个位,A[1]表示a的十位,依次类推。
  将a乘以一个整数k变为将数组A的每一个元素都乘以k,请注意处理相应的进位。
  首先将a设为1,然后乘2,乘3,当乘到n时,即得到了n!的值。
  
输入格式
  输入包含一个正整数n,n<=1000。
输出格式
  输出n!的准确值。
  
样例输入
10
样例输出
3628800

阶乘通常使用递归来计算 Fn = n*Fn-1
但如果深度过大,则会导致超时

n = int(input())
ans = 1
while n: #直接使用循环来计算
    ans *=n
    n -=1
print(ans)

你可能感兴趣的:(Python算法)