from math import inf
def Dijkstra(sourse, adj):
''' 单源最短路径 (不带负权)
sourse: 源点
adj: 图的邻接矩阵'''
vex_num = len(adj)
distance = [inf] * vex_num
distance[sourse] = 0
# 记录单源最短路
undone = [True] * vex_num
# 记录是否未完成
while 1:
min_idx = -1
min_val = inf
for idx, (dist, flag) in enumerate(zip(distance, undone)):
if flag and dist < min_val:
min_val = dist
min_idx = idx
# 找到 min_idx, min_dist
if min_idx != -1:
undone[min_idx] = False
for idx, (dist, flag) in enumerate(zip(distance, undone)):
if flag:
state = min_val + adj[min_idx][idx]
distance[idx] = min([state, distance[idx]])
else:
return distance
def SPFA(sourse, adj):
''' 单源最短路径 (带负权)
sourse: 源点
adj: 图的邻接矩阵'''
vex_num = len(adj)
distance = [inf] * vex_num
distance[sourse] = 0
# 记录单源最短路
exist = [False] * vex_num
exist[sourse] = True
# 记录是否存在队列中
count = [0] * vex_num
count[sourse] = 1
# 记录进入队列的次数
queue = [sourse]
# 初始化队列
while queue:
visit = queue.pop(0)
cur_dist = distance[visit]
exist[visit] = False
# 队列: 弹出当前访问点
for next_, weight in enumerate(adj[visit]):
dist, flag, cnt = distance[next_], exist[next_], count[next_]
new_dist = cur_dist + weight
if new_dist < dist:
dist = new_dist
# 更新: 出边dist值
if not flag:
flag = True
cnt += 1
queue.append(next_)
# 入队: 被更新点
if cnt > vex_num:
return False
# 终止: 存在负环
distance[next_], exist[next_], count[next_] = dist, flag, cnt
return distance
def Floyd(adj):
''' 多源最短路径 (带负权)
adj: 图的邻接表'''
vertex_num = len(adj)
dist = adj.copy()
for pass_p in range(vertex_num):
for sourse in range(vertex_num):
for end in range(vertex_num):
attempt = dist[sourse][pass_p] + dist[pass_p][end]
dist[sourse][end] = min([dist[sourse][end], attempt])
蓝桥杯【第11届决赛】补给 Python 20分https://hebitzj.blog.csdn.net/article/details/122792925
from math import inf
def Prim(sourse, adj):
''' 最小生成树
sourse: 源点
adj: 图的邻接表'''
low_cost = adj[sourse].copy()
last_vex = [sourse] * len(adj)
# 记录 low_cost 中的边权对应的起点
undone = [True] * len(adj)
undone[sourse] = False
# 记录顶点是否已作为出点
edges = []
while any(undone):
next_ = low_cost.index(min(low_cost))
begin = last_vex[next_]
edges.append((begin, next_))
# 找到权值最小边的端点
low_cost[next_] = inf
undone[next_] = False
# 标记出点
for idx, (old, new, flag) in enumerate(zip(low_cost, adj[next_], undone)):
if flag and old > new:
# 满足更优则更新
low_cost[idx] = new
last_vex[idx] = next_
return edges
from math import inf
def topo_sort(in_degree, adj):
''' AOV网拓扑排序 (最小字典序)
in_degree: 入度表
adj: 图的邻接矩阵'''
seq = []
while 1:
visit = -1
for idx, degree in enumerate(in_degree):
if degree == 0:
visit = idx
in_degree[idx] = inf
seq.append(visit)
# 记录: 入度为0的顶点
for out, weight in enumerate(adj[visit]):
if 0 < weight < inf:
in_degree[out] -= 1
break
if visit == -1:
break
# 搜索结束 / 存在环: 退出
return seq
def Euler_path(sourse, adj, search):
''' 欧拉路径 (遍历边各1次)
sourse: 路径起点
adj: 图的邻接表
search: 出边搜索函数'''
path = []
stack = [sourse]
while stack:
visit = stack[-1]
out = adj[visit]
# 访问: 栈顶顶点
if out:
visit, out = search(visit, out)
if out:
stack.append(visit)
# 入栈: 尚未满足途径点条件
else:
path.append(visit)
# 入列: 满足途径点条件
else:
path.append(stack.pop(-1))
# 入列: 满足途径点条件
path.reverse()
return path
def next_permutation(seq):
''' 找到下个字典序
exp: 8 3 7 6 5 4 2 1
| | '''
n = len(seq)
left = -1
for idx in range(n - 2, -1, -1):
if seq[idx] < seq[idx + 1]:
# 找到顺序区的右边界
left = idx
break
if left != -1:
left_val = seq[left]
for right in range(n - 1, left, -1):
right_val = seq[right]
if left_val < right_val:
# 找到交换位
seq[left] = right_val
seq[right] = left_val
seq[left + 1:] = reversed(seq[left + 1:])
# 逆转逆序区
return seq
else:
return None
蓝桥杯 算法训练 数字游戏 Python 90分https://blog.csdn.net/qq_55745968/article/details/122775005
def Pascal_triangle(num):
''' 杨辉三角'''
basic = 1
cont = [basic]
ele, is_even = divmod(num + 1, 2)
# ele为不重复元素的边界
for idx in range(1, ele):
basic *= (num - idx) / idx
cont.append(round(basic))
if is_even:
mirror = cont[::-1]
# 偶数行: 无需回溯
else:
mirror = cont[:-1:-1]
# 奇数行: 需回溯
cont.extend(mirror)
return cont
蓝桥杯 算法训练 数字游戏 Python 90分https://blog.csdn.net/qq_55745968/article/details/122775005
def is_comp(num):
''' 判断合数
return: 最小因数'''
if num <= 3:
return False
if not num & 1:
# 是偶数
return 2
bound = int(num ** 0.5)
# 搜索边界
for mod in range(3, bound + 1, 2):
if not num % mod:
return mod
return False
def prime_filter(num):
''' 质数筛选
return: 筛选结果'''
bound = int(num ** 0.5)
result = [True] * (num + 1)
# 初始化质数标志矩阵
result[1] = False
for mod in range(2, bound + 1):
if result[mod]:
# 找到质数,并作为最小因数
for choose in range(mod ** 2, num + 1, mod):
# 枚举合数: 最小因数的倍数
result[choose] = False
result.pop(0)
return result
def quick_power(basic, time, mod):
''' 二分快速幂
mod: 求余数'''
result = 1
while time:
if time & 1:
result = result * basic % mod
basic = basic ** 2 % mod
time >>= 1
return result
蓝桥杯 算法训练 数的潜能 Python 100分https://hebitzj.blog.csdn.net/article/details/122775159
from math import gcd
def lcm(x, y):
''' 最小公倍数'''
return x * y // gcd(x, y)
import heapq
class Min_Heap(list):
''' 小根堆'''
def __init__(self, seq=[]):
super(Min_Heap, self).__init__(seq)
heapq.heapify(self)
def push(self, ele):
# 元素入堆
heapq.heappush(self, ele)
def poproot(self):
# 弹出堆顶元素并重排
return heapq.heappop(self)
import heapq
class Max_Heap(list):
''' 大根堆'''
def __init__(self, seq=[]):
super(Max_Heap, self).__init__(self._negative(seq))
heapq.heapify(self)
def push(self, ele):
# 元素入堆
heapq.heappush(self, - ele)
def poproot(self):
# 弹出堆顶元素并重排
return - heapq.heappop(self)
def _negative(self, seq):
# 数值取反
return map(lambda x: -x, seq)
def value(self):
return list(self._negative(self))