1. 最大降雨量
问题是求中位数的中位数,上面解题思路图便于理解
import os
import sys
# 请在此输入您的代码
# 降雨量为 7 周能量的中位数。
#1-7
#8-14
#15-21
#22-28
#29-35
#36-42
#43-49
#22-49 =28
# 后面28天尽可能的相同,这样中位数才能大
# 22+49 23+48 24+47 34
# 25+46 26+45 27+44 35
# 28+43 29+42 30+41 36
# 31+40 32+39 33+38 37
print(34)
2.最短路算法比较
3.Floyd算法 (多对多,可以简化成一对多或者多对一)
动态规划 ,原理
计算过程,结合图形理解
计算步骤(将k从1扩展到n)
数组滚动简化方程 (细看,k只用到了上一层,所以可以简化,直接舍去不要)
def floyd():
global dp
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])
dp = [[99999999 for _ in range(N) for _ in range(N)] #dp[i,j]表示i到j最短路径
Floyd例题1
两种写法
import math
def floyd():
global dp
for k in range(1,2022):
#for i in range(1,2022):
for i in range(1,2):
for j in range(1,2022):
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j])
dp = [[9999999999 for _ in range(2022)] for _ in range(2022)] #dp[i,j]表示i到j最短路径
for i in range(1,2022):
for j in range(1,2022):
if abs(i-j)<=21:
dp[i][j]=i//math.gcd(i,j)*j
floyd()
print(dp[1][2021])
from math import gcd
def lcm(x,y):
return x//gcd(x,y)*y
dp = [9999999999]*2022 # 点i到1的最短路径
dp[1]=0 #到自身的距离为0
for i in range(1,2022): # 1-2022
for j in range(i+1,i+22): #和i有边的点j
if j>2021:
break
dp[j] = min(dp[j],dp[i]+lcm(i,j)) # 更新最短路
print(dp[2021])
4.Dijkstra
算法实现
举例说明:
例题:
import heapq #导入堆,默认是小顶堆
def dij(s):
done = [0 for i in range(n+1)] # A:已确定为最短路径的点
hp=[] # 创建一个空堆
dis[s]=0 #到自身的距离
heapq.heappush(hp,(0,s)) # B:A的点向外扩散的邻居点,在堆中根据距离排序(从小到大)
while hp:
u = heapq.heappop(hp)[1] # 弹出最小元素
if done[u]: #表示被处理过了,起到了一个去重,更新小值的作用
continue
done[u]=1
for i in range(len(G[u])): #遍历u的邻居,把u的邻居放入B
v,w = G[u][i] # 邻居v,边长w
if done[v]:
continue
if dis[v]>dis[u]+w:
dis[v]=dis[u]+w
heapq.heappush(hp,(dis[v],v))
n,m = map(int,input().split())
s=1
G = [[] for i in range(n+1)] # 邻接表存图
INF = 2**50
dis = [INF]*(n+1) # 存储距离
for i in range(m): # 读m条边,这里是单向边
u,v,w = map(int,input().split())
G[u].append((v,w)) # 存图,u的一个邻居是v,边长是w
dij(s)
for i in range(1,n+1):
if dis[i]>=INF:print("-1",end=' ')
else:
print(dis[i],end=' ')
5.堆的知识补充
6.最小生成树
通过并查集实现最小生成树的构建,n个点那么最小生成树有n-1条边,当生成的树有n-1条边时跳出构建
聪明的猴子问题
路径问题
import os
import sys
# 请在此输入您的代码
import math
def lcm(i,j):
return i//math.gcd(i,j)*j
dp=[[2**50]*2022 for i in range(2022)]
# 创建图
for i in range(1,2022):
for j in range(i+1,i+22): # 注意边界
if j >2021: break
if abs(i-j)<=21:
dp[i][j]=lcm(i,j)
# 找最短路径
for k in range(1,2022):
for i in range(1,2):
for j in range(1,2022):
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j])
print(dp[1][2021]) # 1026837
蓝桥王国问题
import heapq # 导入堆
def dij(s):
done=[0 for i in range(n+1)] # 记录是否处理过
hp=[] #堆
dis[s]=0
heapq.heappush(hp,(0,s)) #入堆,小顶堆
while hp:
u=heapq.heappop(hp)[1] #出堆元素结点
if done[u]: #当前结点处理过
continue
done[u]=1
for i in range(len(G[u])): #遍历当前结点的邻居
v,w =G[u][i]
if done[v]:continue
dis[v]=min(dis[v],dis[u]+w) # 更新当前结点邻居的最短路径
heapq.heappush(hp,(dis[v],v))
n,m = map(int,input().split())#
s=1 # 从1开始访问
G=[[]for i in range(n+1)] #邻接表存储
inf = 2**50
dis = [inf]*(n+1) #存储距离
for i in range(m):# 存边,这里是单向边
u,v,w = map(int,input().split())
G[u].append((v,w)) #记录结点u的邻居和边长
dij(s)
for i in range(1,n+1):
if dis[i]==inf:
print("-1",end=' ')
else:
print(dis[i],end=' ')
蓝桥公园 问题
import os
import sys
# 请在此输入您的代码
#floyd算法,多对多
def floyd():
global dp
for i in range(1,n+1):
for j in range(1,n+1):
for k in range(1,n+1):
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j])
n,m,q = map(int,input().split())
inf=2**120
dp=[[inf]*(n+1) for i in range(n+1)]
choice=[]
for i in range(m):
u,v,w=map(int,input().split())
dp[u][v]=w
dp[v][u]=w
for i in range(q):
s,d = map(int,input().split())
choice.append((s,d))
floyd()
for s,d in choice:
if dp[s][d]!=inf:
print(dp[s][d])
continue
print(-1)
出差(Dijstra的矩阵形式实现)
import sys
#from typing import List
n, m = map(int, input().split())
# 邻接矩阵
gra = [[float('inf')] * (n+1) for _ in range(n+1)]
dist = [float('inf')] * (n+1)
g = [0] + list(map(int, input().split()))
g[n] = 0
st = [False] * (n+1) # 标志是否被处理过
# 矩阵形式存储实现Dijkstra
def dijkstra():
dist[1] = 0 #到自身距离为0
for _ in range(n - 1): # 循环n-1次,因为还剩下n-1个点
t = -1 #防止出现索引出界问题
for j in range(1, n + 1): #找到没处理过得最小最小距离点
if not st[j] and ( t==-1 or dist[t] > dist[j]):
t = j
for j in range(1, n + 1): # 更新剩下点距离
dist[j] = min(dist[j], dist[t] + gra[t][j])
st[t] = True # 标记为处理过了
return dist[n]
for _ in range(m):
u, v, c = map(int, input().split())
gra[u][v] = g[v] + c
gra[v][u] = g[u] + c
print(dijkstra())
主要掌握(Floyd(多对多(矩阵形式存储)),Dijstra(1对多(邻接表,矩阵))两个算法)
最小生成树问题
熟悉并查集的使用
import math
def set_find(x):
if x==_set[x]:
return _set[x]
else:
_set[x]=set_find(_set[x])
return _set[x]
def set_merge(x,y):
if set_find(x)!=set_find(y): #需要合并
#_set[x]=set_find(y) # 合根指向y的根,这里有问题,即可能只改了一个的指向,要改这个连通块的根结点的指向
_set[set_find(x)]=set_find(y)
_set=[i for i in range(1023)] # 并查集初始化
n1=int(input()) # 猴子个数
m=list(map(int,input().split())) # 读入最大跳入距离
n2=int(input()) #树的个数
location =[0] #方便从1开始
edge_list=[] #存储树的坐标
for i in range(n2): # 存储树的坐标
location.append(list(map(int,input().split())))
# 转换为图,记录每一条边
for i in range(1,n2):
for j in range(i+1,n2+1):
w=math.sqrt((location[i][0]-location[j][0])**2+(location[i][1]-location[j][1])**2)
edge_list.append((i,j,w)) #按照 ( i,j,w ) 形式存储每一条边
# 开始生成最小生成树
maxvalue=0 # 记录生成树的最长边
num=0 #判断已经处理了多少条边
edge_list.sort(key=lambda x:x[2]) # 按边长从小到大排序
for i in edge_list:
if set_find(i[0])!= set_find(i[1]):
set_merge(i[0],i[1])
maxvalue = max(maxvalue,i[2])
num+=1 # 处理了一条边
if num==n2-1: #构建好了n-1条边,完成
break
ans =0
for i in m:
if i>=maxvalue:
ans+=1
print(ans)
官方标答
import math
class Edge:
x = 0
y = 0
w = 0.0
def __init__(self, x, y, w):
self.x = x
self.y = y
self.w = w
def find(x):
if f[x]==x:
return f[x]
else:
f[x] = find(f[x])
return f[x]
def merge(x,y):
xx = find(x)
yy = find(y)
if xx!=yy:
f[yy] = xx
if __name__ == '__main__':
m = int(input())
a = list(map(int, input().split()))
n = int(input())
x = [0 for i in range(n + 2)]
y = [0 for i in range(n + 2)]
for i in range(n):
b = list(map(int, input().split()))
x[i + 1] = b[0]
y[i + 1] = b[1]
edge_list = []
maxvalue = 0
num = 0
for i in range(1, n + 1):
for j in range(i + 1, n + 1):
w = math.sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]))
edge = Edge(i, j, w)
edge_list.append(edge)
edge_list.sort(key=lambda x: x.w)
f = [i for i in range(n + 1)]
for i in edge_list:
if find(i.x)!=find(i.y):
merge(i.x,i.y)
maxvalue = max(maxvalue,i.w)
num+=1
if num==n-1:
break
ans = 0
for i in range(m):
if a[i]>=maxvalue:
ans+=1
print(ans)