当前位置:   article > 正文

蓝桥杯常见算法模板(Python组)_蓝桥杯python组

蓝桥杯python组

目录

1.二分

1.整数二分(二分答案):

2.浮点数二分(考不到)

2.前缀和、差分

1.前缀和

一维:

二维:

2.差分

一维:

二维:

3.贪心

4.线性DP

1.最长上升子序列(子序列问题一般下标从一开始)

2.最长公共子序列

3.常见背包模型

1.0-1背包

2.完全背包

3.多重背包

4.混合背包

5.二维费用背包

6.分组背包

5.搜索

1.DFS

模板:

1.子集问题

2.全排列问题

2.BFS

6.数据结构

1.并查集

2.树状数组

3.树的直径

4.LCA最近公共祖先

7.图论

1.最短路径问题

1.dijkstra算法

2.Floyd算法

3.Bellman-Ford算法

3.拓朴排序

8.数论


1.二分

1.整数二分(二分答案):

!关键是判断是否有单调性 以及如和确定mid是否合法

**常用于最大值最小化、最小值最大化(求最值时也可以考虑)**

  1. #check函数最重要也最难写
  2. def check(x):
  3. #判断x是否合法,合法True,否则False
  4. pass
  5. l,r = #初始化,一般最边界
  6. ans = #初始化
  7. while l <= r:
  8. mid = (l+r)//2
  9. if check(mid):
  10. ans = mid
  11. l = mid + 1#二选一,视题目以及自己定义条件
  12. else:
  13. r = mid - 1

2.浮点数二分(考不到)

  1. def check():
  2. pass
  3. l,r = #初始化
  4. eps = 1e-4
  5. while r - l >= eps:
  6. mid = (l+r)/2
  7. if check(mid):
  8. r = mid#二选一
  9. else:
  10. l = mid

2.前缀和、差分

1.前缀和

一维:

**用于求 区间和  O(1) 算法**

  1. n = int(input())
  2. a = list(map(int,input().split()))
  3. def pre(a):
  4. sum = [0]*n
  5. sum[0] = a[0]
  6. for i in range(1,n):
  7. sum[i] = sum[i-1] + a[i]
  8. return sum
  9. def qiuhe(l,r,sum):
  10. if l == 0:
  11. return sum[0]
  12. else:
  13. return sum[r] - sum[l-1]
二维:
  1. n,m = map(int,input().split())
  2. a = [[0]*(m+1) for i in range(n+1)]
  3. sum = [[0]*(m+1) for i in range(n+1)]
  4. for i in range(1,n+1):
  5. a[i] = [0] + list(map(int,input().split()))
  6. for i in range(1,n+1):
  7. for j in range(1,m+1):
  8. sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + a[i][j]
  9. def qiuhe(x1,y1,x2,y2,sum):
  10. #左下角加左上角-两外两个角(有三个角移位)
  11. return sum[x2][y2] - sum[x1-1][y1] - sum[x2][y1-1] + sum[x1-1][y1-1]

2.差分

一维:

差分数组求前缀和是原数组

  1. n = int(input())
  2. a = list(map(int,input().split()))
  3. d = [0]*(n)
  4. d[0] = a[0]
  5. for i in range(1,n):
  6. d[i] = a[i] - a[i-1]
  7. #区间增加数 复杂度O(1)
  8. def xiugai(l,r,x):
  9. d[l] += x
  10. d[r + 1] -= x
  11. #对差分数组求前缀和复原数组 不能同时进行修改查询
  12. a[0] = d[0]
  13. for i in range(1,n):
  14. a[i] = a[i-1] + d[i]

二维:
  1. #构造差分数组
  2. n,m =map(int,input().split())
  3. a = [[0]*(m+1) for i in range(n+1)]
  4. diff = [[0]*(m+1) for i in range(n+1)]
  5. for i in range(1,n+1):
  6. a[i] = [0] + list(map(int,input().split()))
  7. #构造差分数组
  8. for i in range(1,n+1):
  9. for j in range(1,m+1):
  10. diff = a[i][j] - a[i-1][j] - a[i][j-1] + a[i-1][j-1]
  11. #原矩阵要增加值 复杂度O(1)
  12. def xiugai(x1,y1,x2,y2,c):
  13. diff[x1][y1] += c
  14. diff[x1][y2 + 1] -= c
  15. diff[x2 + 1][y1] -= c
  16. diff[x2 + 1][y2 + 1] += c
  17. N = 1010
  18. def insert(x1, y1, x2, y2, c):
  19. b[x1][y1] += c
  20. b[x2 + 1][y1] -= c
  21. b[x1][y2 + 1] -= c
  22. b[x2 + 1][y2 + 1] += c
  23. n, m, q = map(int, input().split())
  24. a = [[0] * N for _ in range(N)]
  25. b = [[0] * N for _ in range(N)]
  26. for i in range(1, n + 1):
  27. a[i][1:] = map(int, input().split())
  28. for i in range(1, n + 1):
  29. for j in range(1, m + 1):
  30. insert(i, j, i, j, a[i][j])
  31. while q > 0:
  32. q -= 1
  33. x1, y1, x2, y2, c = map(int, input().split())
  34. insert(x1, y1, x2, y2, c)
  35. for i in range(1, n + 1):
  36. for j in range(1, m + 1):
  37. b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1]
  38. print(b[i][j], end=" ")
  39. print()

3.贪心

**无具体算法,需仔细分析每一步,思考如何由小问题合成大问题,如何求子问题解**

需仔细分析,一般要用到排序

思想:把整个问题分解成多个步骤,在每个步骤,都选取当前步骤的最优方案,直到所有步骤结束;在每一步,都不考虑对后续步骤的影响,在后续步骤中也不能回头改变前面的选择

4.线性DP

处理DP中的大问题和小问题,有两种思路:自顶向下(Top-Down,先大问题再小问题)、自下而上(Bottom-Up,先小问题再大问题)。
编码实现DP时,自顶向下用带记忆化搜索的递归编码,自下而上用递推编码。两种方法的复杂度是一样的,每个子问题都计算一遍,而且只计算一遍。

能用DP求解的问题,一般是求方案数,或者求最值。

***注意考虑边界***

1.最长上升子序列(子序列问题一般下标从一开始)

  1. #最长上升子序列
  2. a = [0] + list(map(int,input().split()))
  3. n = len(a)
  4. #dp[i]表示以i结尾的最长上升子序列
  5. #并且初始为1
  6. dp = [0] + [1]*n
  7. for i in range(1,n):
  8. for j in range(1,i):
  9. if a[i] > a[j]:
  10. dp[i] = max(dp[i],dp[j] + 1)
  11. print(max(dp))

2.最长公共子序列

  1. #最长公共子序列
  2. n,m = map(int,input().split())
  3. a = [0] + list(map(int,input().split()))
  4. b = [0] + list(map(int,input().split()))
  5. #dp[i]表示以i结尾的最长上升子序列
  6. #并且初始为1
  7. dp = [[0]*(m+1) for i in range(n+1)]
  8. for i in range(1,n+1):
  9. for j in range(1,m+1)
  10. if a[i] == b[i]:
  11. dp[i][j] = dp[i-1][j-1] + 1
  12. else:
  13. dp[i][j] = max(dp[i-1][j],dp[i][j-1])
  14. print(dp[n][m])

3.最长回文子串

  1. def longest_palindromic_substring(s):
  2. n = len(s)
  3. if n == 0:
  4. return ""
  5. # 创建一个二维数组 dp,其中 dp[i][j] 表示从索引 i 到 j 的子串是否为回文子串
  6. dp = [[False] * n for _ in range(n)]
  7. # 初始化:所有长度为1的子串都是回文串
  8. for i in range(n):
  9. dp[i][i] = True
  10. start, max_len = 0, 1 # 记录最长回文子串的起始位置和长度
  11. # 动态规划递推
  12. for l in range(2, n + 1): # 枚举子串长度
  13. for i in range(n - l + 1): # 枚举子串的起始位置
  14. j = i + l - 1 # 子串的结束位置
  15. if s[i] == s[j]:
  16. if l == 2 or dp[i + 1][j - 1]:
  17. dp[i][j] = True
  18. if l > max_len:
  19. start = i
  20. max_len = l
  21. return s[start:start + max_len]
  22. # 测试
  23. s = input().strip()
  24. print(longest_palindromic_substring(s))

3.常见背包模型

1.0-1背包
  1. n,v = map(int,input().split())
  2. dp = [[0]*(v+1) for i in range(n+1)]
  3. for i in range(1,n+1):
  4. wi,vi = map(int,input().split())
  5. for j in range(v+1):
  6. if j < wi:
  7. dp[i][j] = dp[i-1][j]
  8. else:
  9. dp[i][j] = max(dp[i-1][j],dp[i-1][j-wi] + vi)
  10. #滚动数组优化
  11. #只用到一维 由于每一项与上一行的前一项有关,故需要从后向前更新
  12. #并且if 选项不再需要(只有一维)
  13. n,v = map(int,input().split())
  14. dp = [0]*(v+1)
  15. for i in range(1,n+1):
  16. wi,vi = map(int,input().split())
  17. for j in range(v,wi-1):
  18. dp[j] = max(dp[j],dp[j-wi]+vi)
2.完全背包
  1. n,v = map(int,input().split())
  2. dp = [[0]*(v+1) for i in range(n+1)]
  3. for i in range(1,n+1):
  4. wi,vi = map(int,input().split())
  5. for j in range(v+1):
  6. if j < wi:
  7. dp[i][j] = dp[i-1][j]
  8. else:
  9. dp[i][j] = max(dp[i-1][j],dp[i][j-wi] + vi)
  10. #滚动数组优化
  11. #只用到一维 由于每一项与左边一项有关,故需要从前向后更新
  12. #并且if 选项不再需要
  13. n,v = map(int,input().split())
  14. dp = [0]*(v+1)
  15. #和零一背包区别只在更新方向
  16. for i in range(1,n+1):
  17. wi,vi = map(int,input().split())
  18. for j in range(wi,v+1):
  19. dp[j] = max(dp[j],dp[j-wi]+vi)
3.多重背包
  1. n,v = map(int,input().split())
  2. dp = [[0]*(v+1) for i in range(n+1)]
  3. for i in range(1,n+1):
  4. wi,vi,si = map(int,input().split())
  5. for j in range(v+1):
  6. for k in range(min(si,j//wi)):
  7. dp[i][j] = max(dp[i][j],dp[i-1][j-k*wi] + k*vi)
  8. print(dp[n][v])
  9. #优化成一维背包
  10. #二进制拆分 减少第一维数量 可凑成原来数量
  11. n,v = map(int,input().split())
  12. w_v = []
  13. for i in range(n):
  14. wi,vi,si = map(int,input().split())
  15. k = 1
  16. while si>=k:
  17. w_v.append((k*wi,k*vi))
  18. si-=k
  19. k*=2
  20. if si!=0:
  21. w_v.append((si*wi,si*vi))
  22. for i,(w,v) in enumerate(w_v):
  23. for j in range(v,w-1,-1):
  24. dp[j] = max(dp[j],dp[j-w]+v)
4.混合背包
  1. N, V = map(int, input().split())
  2. dp = [0]*(V+1)
  3. for _ in range(N):
  4. w, v ,n= map(int, input().split())
  5. #如果n为0或者n*w大于等于V,说明该物品只能选择一次或者不能选择,因此直接使用01背包的方式更新dp列表
  6. if n==0 or n*w>=V:
  7. for j in range(w,V+1):
  8. dp[j] = max(dp[j], dp[j-w]+v)
  9. #否则,对于每个物品,使用完全背包的方式更新dp列表。
  10. else :
  11. for k in range(n):
  12. for j in range(V,w-1,-1):
  13. dp[j] = max(dp[j], dp[j-w]+v)
  14. print(dp[-1])
5.二维费用背包
  1. N,V,M = map(int,input().split())
  2. dp = [[0]*(M+1) for i in range(V+1)]
  3. for i in range(N):
  4. v,m,w = map(int,input().split())
  5. for j in range(V,v-1,-1):
  6. for k in range(M,m-1,-1):
  7. dp[j][k] =max(dp[j][k],dp[j-v][k-m] + w)
  8. print(dp[V][M])
6.分组背包
  1. N,V = map(int,input().split())
  2. dp = [[0]*(V+1) for i in range(2)]
  3. for i in range(1,N+1):
  4. s =int(input())
  5. for nn in range(s):
  6. w,v = map(int,input().split())
  7. for j in range(V+1):
  8. if j < w:
  9. dp[i%2][j] = max(dp[i%2][j],dp[(i-1)%2][j])
  10. else:
  11. dp[i%2][j] = max(dp[i%2][j],dp[(i-1)%2][j],dp[(i-1)%2][j-w] + v)
  12. print(dp[N%2][V])

5.搜索

1.DFS

**必考**

n重循环 = 树状结构 = DFS搜索(通常用到标记数组(连通块必用到))

每项选择相互独立 则无需递归

模板:
  1. def dfs(depth):
  2. if depth == n:
  3. *********
  4. return
  5. #条件 + 递归 注意参数 有时候答案可通过参数直接传递

1.子集问题
  1. n = int(input())
  2. a = list(map(int,input().split()))
  3. path = []
  4. def dfs(depth):
  5. if depth == n:
  6. print(path)
  7. return
  8. #选
  9. path.append(a[depth])
  10. dfs(depth + 1)
  11. path.pop()
  12. #不选
  13. dfs(depth + 1)
  14. dfs(0)
2.全排列问题
  1. path = []
  2. vis = [0]*(n+1)
  3. def dfs(x):
  4. if x == n :
  5. print(path)
  6. return
  7. for i in range(1,n+1):
  8. if vis[i] == 0:
  9. path.append(i)
  10. vis[i] = 1
  11. dfs(x+1)
  12. #恢复现场
  13. vis[i] = 0
  14. path.pop()
  15. dfs(0)

2.BFS

思想:全面扩散、逐层递进

***用来求最短路(边长相等)***

  1. from collections import deque
  2. def bfs():
  3. result = []
  4. queue = deque()
  5. queue.append(root)
  6. while queue:
  7. u = queue.popleft()
  8. result.append(u)
  9. for v in G[u]:
  10. queue.append(v)
  11. return result

6.数据结构

1.并查集

  1. import os
  2. import sys
  3. #找父亲
  4. def Findroot(x):
  5. if x == p[x]:
  6. return x
  7. p[x] = Findroot(p[x])#路径压缩
  8. return p[x]
  9. #合并两集合
  10. def Merge(x,y):
  11. rootx = Findroot(x)
  12. rooty = Findroot(y)
  13. p[rootx] = rooty
  14. #查询两集合
  15. def Query(x,y):
  16. rootx = Findroot(x)
  17. rooty = Findroot(y)
  18. return rootx == rooty
  19. N,M = map(int,input().split())
  20. p = list(range(N+1))
  21. for i in range(M):
  22. op,x,y = map(int,input().split())
  23. if op == 1:
  24. Merge(x,y)
  25. else:
  26. if Query(x,y):
  27. print("YES")
  28. else:

2.树状数组

***利用树状数组可在log时间内对数组进行

   1.区间修改:区间+x

   2.单点查询:list[x]

  1. def lowbit(x):
  2. return x&(-x)
  3. #走过的点加y,直到走到最左
  4. def add(x,y):
  5. while x <= n:
  6. tree[x] += y
  7. x += lowbit(x)
  8. #ans += 走过的点 知道走到最右
  9. def query(x):
  10. ans = 0
  11. while x:
  12. ans += tree[x]
  13. x -= lowbit(x)
  14. return ans
  15. n = int(input())
  16. a = [0] + list(map(int,input().split()))
  17. tree = [0]*(n+1)
  18. q = int(input())
  19. for i in range(q):
  20. op,l,r = map(int,input().split())
  21. if op == 1:
  22. add(l,r)
  23. else:
  24. print(query(l)-query(r-1))

3.树的直径

  1. import os
  2. import sys
  3. # 请在此输入您的代码
  4. n = int(input())
  5. G = [[] for i in range(n + 1)]
  6. for _ in range(n - 1):
  7. p, q, d = map(int, input().split())
  8. G[p].append((q, d))
  9. G[q].append((p, d))
  10. # d数组表示每个点的深度
  11. d = [0] * (n + 1)
  12. def dfs(u, fa):
  13. global S
  14. if d[u] > d[S]:
  15. S = u
  16. for v, w in G[u]:
  17. if v == fa:
  18. continue
  19. d[v] = d[u] + w
  20. dfs(v, u)
  21. # S表示最深的点
  22. S = 1
  23. # 从1开始找最深的的
  24. dfs(1, 0)
  25. # 再从S开始找最深的点
  26. d[S] = 0
  27. dfs(S, 0)
  28. print(d[S])

4.LCA最近公共祖先

  1. def dfs(u,fa):
  2. deep[u] + deep[fa] + 1
  3. p[u][0] = fa
  4. for i in range(1,21):
  5. p[u][i] = p[p[u][i-1]][i-1]
  6. for v in G[u]:
  7. if v == fa:
  8. continue
  9. dfs(v,u)
  10. def LCA(x,y):
  11. if deep[x] < deep[y]:
  12. x,y = y,x
  13. #利用倍增方法
  14. #p[x][i] 表示从x节点向上走2^i步
  15. for i in range(20,-1,-1):
  16. if deep[p[x][i]] >= deep[y]:
  17. x = p[x][i]
  18. if x == y:
  19. return x
  20. for i in range(20,-1,-1):
  21. if p[x][i] != p[y][i]:
  22. x,y = p[x][i],p[y][i]
  23. return p[x][0]

7.图论

1.最短路径问题

1.dijkstra算法
  1. # 请在此输入您的代码
  2. #优先队列来做,每次出最小的点
  3. from queue import PriorityQueue
  4. INF = 1e18
  5. def dj(s):
  6. #d数组表示每个点到s的最短距离
  7. d = [INF]*(n+1)
  8. #vis表示其是否已经被更新到最短路径
  9. #其第一次出队列可判断其也被更新到到最短路径
  10. vis = [0]*(n+1)
  11. pq = PriorityQueue()
  12. d[s] = 0
  13. pq.put((d[s],s))#起点放入队列
  14. while not pq.empty():
  15. dis,u = pq.get()
  16. if vis[u] :
  17. continue
  18. vis[u] = 1
  19. for v,w in G[u]:
  20. if d[v] > d[u] + w:
  21. d[v] = d[u] + w
  22. pq.put((d[v],v))
  23. for i in range(1,n+1):
  24. if d[i] == INF :
  25. d[i] = -1
  26. return d[1::]
  27. n,m = map(int,input().split())
  28. G = [[] for i in range(n+1)]
  29. for i in range(m):
  30. u,v,w = map(int,input().split())
  31. G[u].append([v,w])
  32. print(*dj(1),sep = " ")
2.Floyd算法
  1. INF = 1e18
  2. n,m,q = map(int,input().split())
  3. #邻接矩阵来存图
  4. #DP表示点到点的最小距离 dp数组其既是邻接矩阵又是优化算法
  5. dp = [[INF]*(n+1) for i in range(n+1)]
  6. for i in range(n+1):
  7. dp[i][i] = 0
  8. for i in range(m):
  9. u,v,w =map(int,input().split())
  10. dp[u][v] = dp[v][u] = min(dp[u][v],w)# 去重边
  11. #Floyd算法
  12. for k in range(1,n+1):
  13. for i in range(1,n+1):
  14. for j in range(1,n+1):
  15. dp[i][j] = min(dp[i][j],dp[i][k]+ dp[k][j])
  16. for i in range(q):
  17. s,e = map(int,input().split())
  18. if dp[s][e] == INF:
  19. print(-1)
  20. else:
  21. print(dp[s][e])
3.Bellman-Ford算法
  1. n,m = map(int,input().split())
  2. c = [0] + list(map(int,input().split()))
  3. #存边 枚举边
  4. e = []
  5. for i in range(m):
  6. u,v,w = map(int,input().split())
  7. e.append([u,v,w])
  8. e.append([v,u,w])
  9. #表示起点到该点的INF最短距离
  10. INF = 1e9
  11. d = [INF]*(n+1)
  12. d[1] = 0
  13. for i in range(n-1):
  14. for u,v,w in e:
  15. if d[v] > d[u] +w:
  16. d[v] = d[u] +w
  17. print(d[n])

3.拓朴排序

借助队列处理为0的点

  1. from collections import deque
  2. def tuopo():
  3. result = []
  4. q = deque()
  5. #筛选入度空的点
  6. for i in range(1,n+1):
  7. if rudu[i] = 0:
  8. q.append(i)
  9. #只要队列不空
  10. while q:
  11. u = q.popleft()
  12. result.append(u)
  13. for v in G[u]:
  14. rudu[v] -= 1
  15. #再次筛选
  16. if rudu[v] == 0
  17. q.append(v)
  18. if len(result) != n:
  19. print("error")
  20. else:
  21. print(*result,sep = " ")

8.数论

  1. from math import gcd
  2. from math import lcm
  3. #1. gcd 最大公因数
  4. # lcm 最小公倍数
  5. #手写
  6. def gcd(a,b):
  7. if b == 0:
  8. return a
  9. return gcd(b,a%b)
  10. def lcm(a,b):
  11. return a*b//gcd(a,b)
  12. #调用库
  13. # 两个整数的最大公约数
  14. num1 = 12
  15. num2 = 18
  16. result = gcd(num1, num2)
  17. print(f"最大公约数为: {result}")
  18. #2.同余 暴力
  19. res = 1
  20. n = 10000
  21. mod = 10007
  22. for i in range(1,n+1):
  23. res = (res *i) %mod
  24. print(res)
  25. #3.向上取整
  26. print((a+b-1)%b)
  27. #4.素数筛选
  28. #***埃氏筛选
  29. def is_prime(x):
  30. vis = [0]*(n+1)
  31. vis[0] = 1
  32. vis[1] = 1
  33. prime = []
  34. for i in range(1,n+1):
  35. if vis[i] == 0:
  36. prime.append(i)
  37. for m in range(i + i,n+1,i):
  38. vis[m] = 1
  39. return prime
  40. #暴力
  41. def is_prime(n):
  42. """判断一个数是否为素数"""
  43. if n <= 1:
  44. return False
  45. for i in range(2, int(n**0.5) + 1):
  46. if n % i == 0:
  47. return False
  48. return True
  49. #快速幂
  50. #递归
  51. def ksm(a, b):
  52. """快速幂算法,计算 a 的 b 次幂"""
  53. if b == 0:
  54. return 1
  55. # 递归计算 a^(b//2)
  56. ans = ksm(a, b//2)
  57. # 将结果平方
  58. ans = ans * ans
  59. # 如果 b 是奇数,则再乘以一个 a
  60. if b % 2 == 1:
  61. ans = ans * a
  62. return ans
  63. #递推 两种算法效率相同 ***二进制拆分
  64. def ksm(a,b,mod):
  65. res = 1
  66. while b:
  67. if b&1:
  68. res = (res*a)%mod
  69. a = a*a
  70. b >> 1
  71. return res

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/439292
推荐阅读
相关标签
  

闽ICP备14008679号