赞
踩
目录
!关键是判断是否有单调性 以及如和确定mid是否合法
**常用于最大值最小化、最小值最大化(求最值时也可以考虑)**
- #check函数最重要也最难写
- def check(x):
- #判断x是否合法,合法True,否则False
- pass
-
- l,r = #初始化,一般最边界
- ans = #初始化
- while l <= r:
- mid = (l+r)//2
- if check(mid):
- ans = mid
- l = mid + 1#二选一,视题目以及自己定义条件
-
- else:
- r = mid - 1
- def check():
- pass
-
- l,r = #初始化
-
- eps = 1e-4
- while r - l >= eps:
- mid = (l+r)/2
- if check(mid):
- r = mid#二选一
- else:
- l = mid
**用于求 区间和 O(1) 算法**
- n = int(input())
- a = list(map(int,input().split()))
- def pre(a):
- sum = [0]*n
- sum[0] = a[0]
- for i in range(1,n):
- sum[i] = sum[i-1] + a[i]
- return sum
- def qiuhe(l,r,sum):
- if l == 0:
- return sum[0]
- else:
- return sum[r] - sum[l-1]
- n,m = map(int,input().split())
- a = [[0]*(m+1) for i in range(n+1)]
- sum = [[0]*(m+1) for i in range(n+1)]
-
- for i in range(1,n+1):
- a[i] = [0] + list(map(int,input().split()))
-
- for i in range(1,n+1):
- for j in range(1,m+1):
- sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + a[i][j]
-
- def qiuhe(x1,y1,x2,y2,sum):
- #左下角加左上角-两外两个角(有三个角移位)
- return sum[x2][y2] - sum[x1-1][y1] - sum[x2][y1-1] + sum[x1-1][y1-1]
对差分数组求前缀和是原数组
- n = int(input())
- a = list(map(int,input().split()))
- d = [0]*(n)
- d[0] = a[0]
- for i in range(1,n):
- d[i] = a[i] - a[i-1]
-
- #区间增加数 复杂度O(1)
- def xiugai(l,r,x):
- d[l] += x
- d[r + 1] -= x
-
- #对差分数组求前缀和复原数组 不能同时进行修改查询
- a[0] = d[0]
- for i in range(1,n):
- a[i] = a[i-1] + d[i]
- #构造差分数组
- n,m =map(int,input().split())
-
- a = [[0]*(m+1) for i in range(n+1)]
- diff = [[0]*(m+1) for i in range(n+1)]
- for i in range(1,n+1):
- a[i] = [0] + list(map(int,input().split()))
- #构造差分数组
- for i in range(1,n+1):
- for j in range(1,m+1):
- diff = a[i][j] - a[i-1][j] - a[i][j-1] + a[i-1][j-1]
-
- #原矩阵要增加值 复杂度O(1)
- def xiugai(x1,y1,x2,y2,c):
- diff[x1][y1] += c
- diff[x1][y2 + 1] -= c
- diff[x2 + 1][y1] -= c
- diff[x2 + 1][y2 + 1] += c
-
-
- N = 1010
-
- def insert(x1, y1, x2, y2, c):
- b[x1][y1] += c
- b[x2 + 1][y1] -= c
- b[x1][y2 + 1] -= c
- b[x2 + 1][y2 + 1] += c
-
- n, m, q = map(int, input().split())
- a = [[0] * N for _ in range(N)]
- b = [[0] * N for _ in range(N)]
-
- for i in range(1, n + 1):
- a[i][1:] = map(int, input().split())
-
- for i in range(1, n + 1):
- for j in range(1, m + 1):
- insert(i, j, i, j, a[i][j])
-
- while q > 0:
- q -= 1
- x1, y1, x2, y2, c = map(int, input().split())
- insert(x1, y1, x2, y2, c)
-
- for i in range(1, n + 1):
- for j in range(1, m + 1):
- b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1]
- print(b[i][j], end=" ")
- print()
-
-
**无具体算法,需仔细分析每一步,思考如何由小问题合成大问题,如何求子问题解**
需仔细分析,一般要用到排序
思想:把整个问题分解成多个步骤,在每个步骤,都选取当前步骤的最优方案,直到所有步骤结束;在每一步,都不考虑对后续步骤的影响,在后续步骤中也不能回头改变前面的选择
处理DP中的大问题和小问题,有两种思路:自顶向下(Top-Down,先大问题再小问题)、自下而上(Bottom-Up,先小问题再大问题)。
编码实现DP时,自顶向下用带记忆化搜索的递归编码,自下而上用递推编码。两种方法的复杂度是一样的,每个子问题都计算一遍,而且只计算一遍。
能用DP求解的问题,一般是求方案数,或者求最值。
***注意考虑边界***
- #最长上升子序列
- a = [0] + list(map(int,input().split()))
- n = len(a)
- #dp[i]表示以i结尾的最长上升子序列
- #并且初始为1
- dp = [0] + [1]*n
- for i in range(1,n):
- for j in range(1,i):
- if a[i] > a[j]:
- dp[i] = max(dp[i],dp[j] + 1)
- print(max(dp))
- #最长公共子序列
- n,m = map(int,input().split())
- a = [0] + list(map(int,input().split()))
- b = [0] + list(map(int,input().split()))
-
-
- #dp[i]表示以i结尾的最长上升子序列
- #并且初始为1
- dp = [[0]*(m+1) for i in range(n+1)]
- for i in range(1,n+1):
- for j in range(1,m+1)
- if a[i] == b[i]:
- dp[i][j] = dp[i-1][j-1] + 1
- else:
- dp[i][j] = max(dp[i-1][j],dp[i][j-1])
-
- print(dp[n][m])
- def longest_palindromic_substring(s):
- n = len(s)
- if n == 0:
- return ""
-
- # 创建一个二维数组 dp,其中 dp[i][j] 表示从索引 i 到 j 的子串是否为回文子串
- dp = [[False] * n for _ in range(n)]
-
- # 初始化:所有长度为1的子串都是回文串
- for i in range(n):
- dp[i][i] = True
-
- start, max_len = 0, 1 # 记录最长回文子串的起始位置和长度
-
- # 动态规划递推
- for l in range(2, n + 1): # 枚举子串长度
- for i in range(n - l + 1): # 枚举子串的起始位置
- j = i + l - 1 # 子串的结束位置
- if s[i] == s[j]:
- if l == 2 or dp[i + 1][j - 1]:
- dp[i][j] = True
- if l > max_len:
- start = i
- max_len = l
-
- return s[start:start + max_len]
-
- # 测试
- s = input().strip()
- print(longest_palindromic_substring(s))
- n,v = map(int,input().split())
- dp = [[0]*(v+1) for i in range(n+1)]
-
- for i in range(1,n+1):
- wi,vi = map(int,input().split())
- for j in range(v+1):
- if j < wi:
- dp[i][j] = dp[i-1][j]
- else:
- dp[i][j] = max(dp[i-1][j],dp[i-1][j-wi] + vi)
-
- #滚动数组优化
- #只用到一维 由于每一项与上一行的前一项有关,故需要从后向前更新
- #并且if 选项不再需要(只有一维)
- n,v = map(int,input().split())
- dp = [0]*(v+1)
-
- for i in range(1,n+1):
- wi,vi = map(int,input().split())
-
- for j in range(v,wi-1):
- dp[j] = max(dp[j],dp[j-wi]+vi)
- n,v = map(int,input().split())
- dp = [[0]*(v+1) for i in range(n+1)]
-
- for i in range(1,n+1):
- wi,vi = map(int,input().split())
- for j in range(v+1):
- if j < wi:
- dp[i][j] = dp[i-1][j]
- else:
- dp[i][j] = max(dp[i-1][j],dp[i][j-wi] + vi)
- #滚动数组优化
- #只用到一维 由于每一项与左边一项有关,故需要从前向后更新
- #并且if 选项不再需要
- n,v = map(int,input().split())
- dp = [0]*(v+1)
- #和零一背包区别只在更新方向
- for i in range(1,n+1):
- wi,vi = map(int,input().split())
- for j in range(wi,v+1):
- dp[j] = max(dp[j],dp[j-wi]+vi)
- n,v = map(int,input().split())
- dp = [[0]*(v+1) for i in range(n+1)]
-
- for i in range(1,n+1):
- wi,vi,si = map(int,input().split())
-
- for j in range(v+1):
- for k in range(min(si,j//wi)):
- dp[i][j] = max(dp[i][j],dp[i-1][j-k*wi] + k*vi)
- print(dp[n][v])
- #优化成一维背包
- #二进制拆分 减少第一维数量 可凑成原来数量
- n,v = map(int,input().split())
- w_v = []
- for i in range(n):
- wi,vi,si = map(int,input().split())
- k = 1
- while si>=k:
- w_v.append((k*wi,k*vi))
- si-=k
- k*=2
-
- if si!=0:
- w_v.append((si*wi,si*vi))
- for i,(w,v) in enumerate(w_v):
-
- for j in range(v,w-1,-1):
- dp[j] = max(dp[j],dp[j-w]+v)
- N, V = map(int, input().split())
- dp = [0]*(V+1)
- for _ in range(N):
- w, v ,n= map(int, input().split())
- #如果n为0或者n*w大于等于V,说明该物品只能选择一次或者不能选择,因此直接使用01背包的方式更新dp列表
- if n==0 or n*w>=V:
- for j in range(w,V+1):
- dp[j] = max(dp[j], dp[j-w]+v)
- #否则,对于每个物品,使用完全背包的方式更新dp列表。
- else :
- for k in range(n):
- for j in range(V,w-1,-1):
- dp[j] = max(dp[j], dp[j-w]+v)
- print(dp[-1])
- N,V,M = map(int,input().split())
-
- dp = [[0]*(M+1) for i in range(V+1)]
-
- for i in range(N):
- v,m,w = map(int,input().split())
-
- for j in range(V,v-1,-1):
- for k in range(M,m-1,-1):
- dp[j][k] =max(dp[j][k],dp[j-v][k-m] + w)
-
- print(dp[V][M])
- N,V = map(int,input().split())
- dp = [[0]*(V+1) for i in range(2)]
- for i in range(1,N+1):
- s =int(input())
- for nn in range(s):
- w,v = map(int,input().split())
-
- for j in range(V+1):
- if j < w:
- dp[i%2][j] = max(dp[i%2][j],dp[(i-1)%2][j])
- else:
- dp[i%2][j] = max(dp[i%2][j],dp[(i-1)%2][j],dp[(i-1)%2][j-w] + v)
-
-
- print(dp[N%2][V])
**必考**
n重循环 = 树状结构 = DFS搜索(通常用到标记数组(连通块必用到))
每项选择相互独立 则无需递归
- def dfs(depth):
- if depth == n:
- *********
- return
- #条件 + 递归 注意参数 有时候答案可通过参数直接传递
- n = int(input())
- a = list(map(int,input().split()))
-
- path = []
- def dfs(depth):
- if depth == n:
- print(path)
- return
- #选
- path.append(a[depth])
- dfs(depth + 1)
- path.pop()
- #不选
- dfs(depth + 1)
-
-
- dfs(0)
- path = []
- vis = [0]*(n+1)
- def dfs(x):
- if x == n :
- print(path)
- return
-
- for i in range(1,n+1):
- if vis[i] == 0:
- path.append(i)
- vis[i] = 1
- dfs(x+1)
- #恢复现场
- vis[i] = 0
- path.pop()
- dfs(0)
思想:全面扩散、逐层递进
***用来求最短路(边长相等)***
- from collections import deque
- def bfs():
- result = []
- queue = deque()
- queue.append(root)
- while queue:
- u = queue.popleft()
- result.append(u)
- for v in G[u]:
- queue.append(v)
- return result
- import os
- import sys
-
- #找父亲
- def Findroot(x):
- if x == p[x]:
- return x
- p[x] = Findroot(p[x])#路径压缩
- return p[x]
-
- #合并两集合
- def Merge(x,y):
- rootx = Findroot(x)
- rooty = Findroot(y)
- p[rootx] = rooty
- #查询两集合
- def Query(x,y):
- rootx = Findroot(x)
- rooty = Findroot(y)
- return rootx == rooty
-
- N,M = map(int,input().split())
- p = list(range(N+1))
- for i in range(M):
- op,x,y = map(int,input().split())
- if op == 1:
- Merge(x,y)
- else:
- if Query(x,y):
- print("YES")
- else:
***利用树状数组可在log时间内对数组进行
1.区间修改:区间+x
2.单点查询:list[x]
- def lowbit(x):
- return x&(-x)
-
- #走过的点加y,直到走到最左
- def add(x,y):
- while x <= n:
- tree[x] += y
- x += lowbit(x)
-
- #ans += 走过的点 知道走到最右
- def query(x):
- ans = 0
- while x:
- ans += tree[x]
- x -= lowbit(x)
- return ans
-
- n = int(input())
- a = [0] + list(map(int,input().split()))
- tree = [0]*(n+1)
- q = int(input())
-
- for i in range(q):
- op,l,r = map(int,input().split())
- if op == 1:
- add(l,r)
- else:
- print(query(l)-query(r-1))
- import os
- import sys
-
- # 请在此输入您的代码
- n = int(input())
-
- G = [[] for i in range(n + 1)]
-
- for _ in range(n - 1):
- p, q, d = map(int, input().split())
-
- G[p].append((q, d))
- G[q].append((p, d))
-
- # d数组表示每个点的深度
- d = [0] * (n + 1)
-
-
- def dfs(u, fa):
- global S
- if d[u] > d[S]:
- S = u
-
- for v, w in G[u]:
- if v == fa:
- continue
- d[v] = d[u] + w
- dfs(v, u)
-
-
- # S表示最深的点
- S = 1
- # 从1开始找最深的的
- dfs(1, 0)
- # 再从S开始找最深的点
- d[S] = 0
- dfs(S, 0)
- print(d[S])
- def dfs(u,fa):
- deep[u] + deep[fa] + 1
- p[u][0] = fa
- for i in range(1,21):
- p[u][i] = p[p[u][i-1]][i-1]
- for v in G[u]:
- if v == fa:
- continue
- dfs(v,u)
-
-
-
-
- def LCA(x,y):
-
- if deep[x] < deep[y]:
- x,y = y,x
- #利用倍增方法
- #p[x][i] 表示从x节点向上走2^i步
- for i in range(20,-1,-1):
- if deep[p[x][i]] >= deep[y]:
- x = p[x][i]
- if x == y:
- return x
-
- for i in range(20,-1,-1):
- if p[x][i] != p[y][i]:
- x,y = p[x][i],p[y][i]
- return p[x][0]
- # 请在此输入您的代码
- #优先队列来做,每次出最小的点
- from queue import PriorityQueue
- INF = 1e18
- def dj(s):
- #d数组表示每个点到s的最短距离
- d = [INF]*(n+1)
- #vis表示其是否已经被更新到最短路径
- #其第一次出队列可判断其也被更新到到最短路径
- vis = [0]*(n+1)
- pq = PriorityQueue()
- d[s] = 0
- pq.put((d[s],s))#起点放入队列
- while not pq.empty():
- dis,u = pq.get()
- if vis[u] :
- continue
- vis[u] = 1
- for v,w in G[u]:
- if d[v] > d[u] + w:
- d[v] = d[u] + w
- pq.put((d[v],v))
- for i in range(1,n+1):
- if d[i] == INF :
- d[i] = -1
-
- return d[1::]
-
-
-
- n,m = map(int,input().split())
- G = [[] for i in range(n+1)]
- for i in range(m):
- u,v,w = map(int,input().split())
- G[u].append([v,w])
-
- print(*dj(1),sep = " ")
- INF = 1e18
- n,m,q = map(int,input().split())
- #邻接矩阵来存图
- #DP表示点到点的最小距离 dp数组其既是邻接矩阵又是优化算法
- dp = [[INF]*(n+1) for i in range(n+1)]
- for i in range(n+1):
- dp[i][i] = 0
- for i in range(m):
- u,v,w =map(int,input().split())
- dp[u][v] = dp[v][u] = min(dp[u][v],w)# 去重边
- #Floyd算法
- for k in range(1,n+1):
- for i in range(1,n+1):
- for j in range(1,n+1):
- dp[i][j] = min(dp[i][j],dp[i][k]+ dp[k][j])
-
-
- for i in range(q):
- s,e = map(int,input().split())
- if dp[s][e] == INF:
- print(-1)
- else:
- print(dp[s][e])
- n,m = map(int,input().split())
- c = [0] + list(map(int,input().split()))
- #存边 枚举边
- e = []
- for i in range(m):
- u,v,w = map(int,input().split())
- e.append([u,v,w])
- e.append([v,u,w])
- #表示起点到该点的INF最短距离
- INF = 1e9
- d = [INF]*(n+1)
- d[1] = 0
- for i in range(n-1):
- for u,v,w in e:
- if d[v] > d[u] +w:
- d[v] = d[u] +w
- print(d[n])
借助队列处理为0的点
- from collections import deque
- def tuopo():
- result = []
- q = deque()
- #筛选入度空的点
- for i in range(1,n+1):
- if rudu[i] = 0:
- q.append(i)
- #只要队列不空
- while q:
- u = q.popleft()
- result.append(u)
- for v in G[u]:
- rudu[v] -= 1
- #再次筛选
- if rudu[v] == 0
- q.append(v)
- if len(result) != n:
- print("error")
- else:
- print(*result,sep = " ")
- from math import gcd
- from math import lcm
-
- #1. gcd 最大公因数
- # lcm 最小公倍数
- #手写
- def gcd(a,b):
- if b == 0:
- return a
- return gcd(b,a%b)
- def lcm(a,b):
- return a*b//gcd(a,b)
-
-
- #调用库
- # 两个整数的最大公约数
- num1 = 12
- num2 = 18
- result = gcd(num1, num2)
- print(f"最大公约数为: {result}")
-
-
- #2.同余 暴力
- res = 1
- n = 10000
- mod = 10007
- for i in range(1,n+1):
- res = (res *i) %mod
-
- print(res)
-
-
- #3.向上取整
- print((a+b-1)%b)
-
- #4.素数筛选
- #***埃氏筛选
- def is_prime(x):
- vis = [0]*(n+1)
- vis[0] = 1
- vis[1] = 1
- prime = []
- for i in range(1,n+1):
- if vis[i] == 0:
- prime.append(i)
- for m in range(i + i,n+1,i):
- vis[m] = 1
- return prime
- #暴力
- def is_prime(n):
- """判断一个数是否为素数"""
- if n <= 1:
- return False
- for i in range(2, int(n**0.5) + 1):
- if n % i == 0:
- return False
- return True
-
-
- #快速幂
- #递归
- def ksm(a, b):
- """快速幂算法,计算 a 的 b 次幂"""
- if b == 0:
- return 1
- # 递归计算 a^(b//2)
- ans = ksm(a, b//2)
- # 将结果平方
- ans = ans * ans
- # 如果 b 是奇数,则再乘以一个 a
- if b % 2 == 1:
- ans = ans * a
- return ans
-
- #递推 两种算法效率相同 ***二进制拆分
- def ksm(a,b,mod):
- res = 1
- while b:
- if b&1:
- res = (res*a)%mod
- a = a*a
- b >> 1
- return res
-
-
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。