算法python
1e6是double类型,要写的话要写成int(1e6)+10
模版
import heapq
import math
import os
import sys
from collections import deque
from bisect import bisect_left
import datetime
if os.path.exists("input.txt"):
sys.stdin=open("input.txt","r")
## sys.stdout=open("output.txt","w")
def main():
n=int(input())
a=list(map(int,input().split()))
if __name__ == '__main__':
main();
数组
# 1. 快速初始化 (竞赛最常用)
n, m = 5, 3
dp = [0] * n # 一维初始化: [0, 0, 0, 0, 0]
# 二维初始化 (严禁使用 [[0]*n]*m,会产生引用陷阱)
grid = [[0] * n for _ in range(m)] # 3行5列的零矩阵
nums = list(range(10)) # 生成 0-9 的列表
# 2. 核心增删 (模拟栈 Stack)
stack = [1, 2]
stack.append(3) # 末尾添加: [1, 2, 3] -> O(1)
top = stack.pop() # 弹出末尾: 3, 列表变为 [1, 2] -> O(1)
stack.extend([4, 5]) # 合并列表: [1, 2, 4, 5] -> O(k)
# 3. 排序与反转 (算法灵魂)
a = [3, 1, 4, 1, 5, 9]
a.sort() # 原地升序: [1, 1, 3, 4, 5, 9] -> O(n log n)
a.sort(reverse=True) # 原地降序: [9, 5, 4, 3, 1, 1]
# 高级排序:按绝对值排序
b = [-5, 2, -1, 3]
b.sort(key=lambda x: abs(x)) # [-1, 2, 3, -5]
# 4. 强大的切片 (Slicing)
nums = [0, 1, 2, 3, 4, 5]
print(nums[1:4]) # 左闭右开: [1, 2, 3]
print(nums[::-1]) # 快速反转: [5, 4, 3, 2, 1, 0]
print(nums[::2]) # 步长取值: [0, 2, 4]
# 5. 查找与统计 (注意复杂度!)
ls = [1, 2, 2, 3]
print(2 in ls) # 是否存在: True -> O(n)
print(ls.count(2)) # 计数: 2 -> O(n)
print(ls.index(3)) # 查找索引: 3 -> O(n)
# 6. 常用内置聚合函数
print(len(ls)) # 长度: 4
print(sum(ls)) # 求和: 8
print(max(ls)) # 最大值: 3
print(min(ls)) # 最小值: 1
# 7. 列表推导式 (List Comprehension - 提速利器)
# 过滤掉所有偶数并求平方
squares = [x**2 for x in range(10) if x % 2 != 0] # [1, 9, 25, 49, 81]
# 8. 遍历
for i, val in enumerate(ls): # 同时获取索引和值
print(f"Index {i}: {val}")
字典
# 1. 创建字典
d1 = {"apple": 1, "banana": 2}
d2 = dict([("a", 1), ("b", 2)])
# 竞赛技巧:初始化计数器 (若 key 不存在则默认值为 0)
from collections import defaultdict
d3 = defaultdict(int)
# 2. 访问与修改
print(d1["apple"]) # 访问: 1 (若 key 不存在会报错)
print(d1.get("pear", 0)) # 安全访问: 返回 0 (若 key 不存在返回默认值)
d1["cherry"] = 3 # 新增/修改: {"apple": 1, "banana": 2, "cherry": 3}
# 3. 核心特性
# Key 必须是不可变类型(如 int, str, tuple),不能是 list
# 4. 常用方法
print("apple" in d1) # 成员检查: True -> O(1)
print(d1.keys()) # 获取所有键
print(d1.values()) # 获取所有值
print(d1.items()) # 获取所有键值对
del d1["apple"] # 删除键值对
val = d1.pop("banana") # 弹出并返回: 2
# 5. 遍历字典
for key, value in d1.items():
print(f"{key}: {value}")
# 6. 字典推导式
# 快速交换键值对
new_d = {v: k for k, v in d2.items()}
集合
# 1. 创建集合
s1 = {1, 2, 3}
s2 = set([3, 4, 5])
s3 = set() # 注意:空集合必须用 set(),{} 是空字典
# 2. 修改元素
s1.add(4) # 添加: {1, 2, 3, 4} -> O(1)
s1.remove(4) # 删除: {1, 2, 3} (不存在会报错)
s1.discard(10) # 安全删除: 10 不存在也不报错
# 3. 集合运算 (竞赛高频)
print(s1 | s2) # 并集: {1, 2, 3, 4, 5} (所有元素)
print(s1 & s2) # 交集: {3} (共有元素)
print(s1 - s2) # 差集: {1, 2} (s1 有但 s2 没有)
print(s1 ^ s2) # 对称差集: {1, 2, 4, 5} (不共有的元素)
# 4. 常用统计
print(len(s1)) # 长度: 3
print(2 in s1) # 存在性检查: True -> O(1) (列表则是 O(n))
# 5. 快速去重
lst = [1, 2, 2, 3, 3]
unique_lst = list(set(lst)) # [1, 2, 3]
# 6. 遍历集合
for x in s1:
print(x)
元组
# 1. 创建元组
t1 = (1, 2, 3)
t2 = tuple([4, 5, 6])
t3 = (10,) # 竞赛技巧:创建单个元素的元组必须加逗号,否则会被识别为括号表达式
empty_t = () # 空元组
# 2. 访问与拆包 (Unpacking)
print(t1[0]) # 访问: 1 (支持负数索引 t1[-1])
print(t1[1:3]) # 切片: (2, 3) -> 返回新元组
x, y, z = t1 # 核心技巧:快速拆包,常用于坐标处理 x, y = pos
a, *mid, b = (1, 2, 3, 4, 5) # 进阶拆包:a=1, mid=[2,3,4], b=5
# 3. 核心特性
# 不可变性:元组一旦创建,其元素不能被修改、新增或删除。
# 性能优势:比 list 占用内存更小,创建速度更快。
# 字典键值:元组可作为 dict 的 key 或 set 的元素(前提是元组内的元素也必须是不可变的)。
# 4. 常用方法
t = (1, 2, 2, 3)
print(len(t)) # 获取长度: 4
print(t.count(2)) # 统计个数: 2
print(t.index(3)) # 查找索引: 3 (若不存在会报错)
print(1 in t) # 成员检查: True -> O(n)
# 5. 常见竞赛操作
# 连接与重复
t_combined = t1 + t2 # 合并: (1, 2, 3, 4, 5, 6)
t_repeat = (0,) * 5 # 快速初始化固定长度的全 0 元组: (0, 0, 0, 0, 0)
# 排序 (元组本身不可变,排序会返回 list)
sorted_list = sorted((3, 1, 2)) # 返回 [1, 2, 3]
# 6. 进阶:具名元组 (Namedtuple)
# 在处理类似“点(x, y)”或“学生(name, score)”的数据时,增加代码可读性且不损失性能
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(11, y=22)
print(p.x, p.y) # 像访问对象属性一样访问索引
输入输出
输入
strip():移除字符串开头和结尾的指定字符(默认为空白符,包括空格 、换行 \n、制表符 \t)。它不会影响字符串中间的内容。
split():根据指定的分隔符将一个字符串拆分成一个列表
import sys
# 1. 终极提速:替换 input 函数
# readline() 保留换行符,速度比 input() 快 5-10 倍
input = sys.stdin.readline
# 2. 读取多个整数
# 比如输入: 1 2 3
a, b, c = map(int, input().split())
# 3. 读取整行并转化为列表
nums = list(map(int, input().split()))
# 4. 读取二维矩阵 (n 行)
grid = [list(map(int, input().split())) for _ in range(n)]
# 5. 一次性读取所有内容 (适用于内存充足、输入量巨大的情况)
# data 是一个包含所有单词/数字的列表
data = sys.stdin.read().split()
| 函数 | 读取范围 | 结果类型 | 包含换行符吗 |
|---|---|---|---|
input() |
读取当前一行 | 字符串 | 否 |
sys.stdin.readline() |
读取当前一行 | 字符串 | 是(末尾带 \n) |
sys.stdin.read() |
读取整个文件直到 EOF | 字符串 | 是 |
.splitlines() |
作用于字符串 | 列表 | 否(自动处理所有平台的换行符) |
输出
# 1. 空格分隔输出
# 等价于 print(lst[0], lst[1], ...)
lst = [1, 2, 3, 4]
print(*lst) # 输出: 1 2 3 4
# 2. 换行分隔输出 (用 join 代替 for 循环)
# 注意:join 只能拼接字符串,所以需要先 map 转化
print("\n".join(map(str, lst)))
# 3. 格式化输出 (F-string 最快)
ans = 42
print(f"Case #1: {ans}")
# 4. 极致输出 (sys.stdout.write)
# 相比 print,它不会自动加换行,且少了参数解析开销
sys.stdout.write(" ".join(map(str, lst)) + "\n")
双端队列
运算法则
正无穷大 (Max): float('inf')
负无穷大 (Min): float('-inf')
除法
x //= i #整数除法
x /= i #浮点数除法
sort和sorted区别
| 特性 | list.sort() 方法 |
sorted() 函数 |
|---|---|---|
| 修改对象 | 原地修改 (In-place)。直接改变原始列表。 | 不改变原对象。返回一个排好序的新列表。 |
| 返回值 | None。不返回任何对象。 | 新列表。返回包含排序后元素的新 list。 |
| 适用对象 | 仅限列表 (list)。 | 任何可迭代对象 (Iterable)。如元组、字典、字符串等。 |
| 内存开销 | 较低。因为它是在原内存地址上进行操作。 | 较高。需要额外的空间来存储返回的新列表。 |
两者都接受 key 参数(用于指定排序规则的函数)和 reverse 参数(布尔值,决定升序还是降序)。
指定排序范围
- 只对部分范围排序,并接回原列表
这是最常用的做法。以取出需要排序的部分,排序后再用切片赋值的方式把它们放回去。
a = [0, 5, 1, 4, 2]
# 假设我们只想对索引 1 到 3 的元素排序(即 [5, 1, 4])
# 切片 a[1:4] 取出的是索引 1, 2, 3
a[1:4] = sorted(a[1:4])
print(a) # 输出: [0, 1, 4, 5, 2]
- 使用
sort()方法(原地修改)
不想创建新列表,可以先切片赋值给一个临时变量,排序后再放回。但通常直接配合切片赋值更简洁:
# 语法:列表[起始:结束] = sorted(列表[起始:结束])
a[2:] = sorted(a[2:]) # 从索引 2 开始到最后排序
deque
from collections import deque
# 1. 创建双端队列
dq = deque([1, 2, 3])
dq_empty = deque()
dq_limit = deque(maxlen=5) # 竞赛技巧:设置固定长度,超出时会自动丢弃另一端元素,常用于滑动窗口
# 2. 基础增删操作 (O(1) 复杂度)
dq.append(4) # 右侧添加: [1, 2, 3, 4]
dq.appendleft(0) # 左侧添加: [0, 1, 2, 3, 4]
val_r = dq.pop() # 右侧弹出: 4 (若为空会抛出 IndexError)
val_l = dq.popleft() # 左侧弹出: 0 (核心技巧:这是 deque 优于 list 的关键)
# 3. 访问与搜索
print(dq[0]) # 访问队头: 1 (支持索引访问,但 O(n) 复杂度)
print(dq[-1]) # 访问队尾: 3
# 注意:deque 的索引访问效率低于 list,竞赛中尽量只访问两端
# 4. 核心特性
# 效率优势:popleft() 和 appendleft() 时间复杂度为 O(1),而 list.pop(0) 为 O(n)
# 线程安全:deque 是线程安全的,但在单线程竞赛环境下主要关注其速度
# 适用场景:广度优先搜索 (BFS)、单调队列优化、滑动窗口最大值/最小值
# 5. 常用方法
dq.extend([4, 5]) # 右侧扩展: [1, 2, 3, 4, 5]
dq.extendleft([-1, 0]) # 左侧扩展: [0, -1, 1, 2, 3, 4, 5] (注意顺序是逆向的)
dq.rotate(1) # 循环右移: [5, 0, -1, 1, 2, 3, 4] (将队尾移到队头)
dq.rotate(-1) # 循环左移: [0, -1, 1, 2, 3, 4, 5]
dq.count(1) # 统计元素个数: 1
dq.clear() # 清空队列
# 6. 常见竞赛操作
# BFS 模板片段
# queue = deque([start_node])
# while queue:
# curr = queue.popleft()
# for neighbor in curr.neighbors:
# if neighbor not in visited:
# queue.append(neighbor)
# 转换为 list
list_version = list(dq) # 某些情况下需要切片操作时转换,O(n)
# 检查是否为空
if not dq: # 竞赛技巧:直接判断是否为空,比 len(dq) == 0 更快
print("Queue is empty")
heapq
import heapq
# heapq 默认是小根堆:堆顶 heap[0] 永远是当前最小值
# 注意:它不是排序好的列表,只保证 heap[0] 最小
# 1. 创建堆
h = []
heapq.heappush(h, 3) # 插入元素: O(log n)
heapq.heappush(h, 1)
heapq.heappush(h, 2)
print(h[0]) # 查看堆顶最小值: 1 -> O(1),不弹出
# 2. 弹出堆顶
x = heapq.heappop(h) # 弹出并返回最小值: 1 -> O(log n)
# 3. 把普通列表变成堆
a = [5, 1, 3, 2, 4]
heapq.heapify(a) # 原地建堆: O(n),比一个个 heappush 更快
print(a[0]) # 当前最小值: 1
# 4. 边插入边弹出
h = [1, 3, 5]
heapq.heapify(h)
heapq.heappushpop(h, 2) # 先 push 再 pop,返回较小的那个: 1
heapq.heapreplace(h, 4) # 先 pop 再 push,返回原堆顶: 2
# 区别:
# heappushpop(h, x):适合“只保留更大的元素”
# heapreplace(h, x):无论 x 多小,都会先弹出堆顶
# 5. 模拟大根堆
# Python 没有直接的大根堆,常用做法是存负数
max_heap = []
for x in [3, 1, 5, 2]:
heapq.heappush(max_heap, -x)
mx = -heapq.heappop(max_heap) # 弹出最大值: 5
# 6. 存元组:按第一个元素排序,第一个相同再比第二个
# 常用于 Dijkstra / A* / 按优先级处理任务
pq = []
heapq.heappush(pq, (10, "a")) # (优先级, 数据)
heapq.heappush(pq, (3, "b"))
heapq.heappush(pq, (3, "c"))
priority, node = heapq.heappop(pq) # (3, "b")
# 7. 求前 k 大 / 前 k 小
nums = [7, 1, 5, 2, 9, 3]
k = 3
print(heapq.nsmallest(k, nums)) # 最小的 k 个: [1, 2, 3]
print(heapq.nlargest(k, nums)) # 最大的 k 个: [9, 7, 5]
# 竞赛中更常见的写法:维护一个大小为 k 的小根堆,求前 k 大
h = []
for x in nums:
heapq.heappush(h, x)
if len(h) > k:
heapq.heappop(h) # 弹掉当前最小值
print(h) # 剩下的就是最大的 k 个数,堆顶是第 k 大
# 8. 懒删除技巧
# heapq 不支持 O(log n) 删除任意元素,通常用 dict / set 标记“已经删除”
h = []
deleted = set()
for x in [1, 2, 3, 4]:
heapq.heappush(h, x)
deleted.add(1) # 假装删除 1
while h and h[0] in deleted:
heapq.heappop(h) # 真正用到堆顶时再删
math库
import math
# 1. 数论运算 (竞赛核心)
a, b = 12, 18
print(math.gcd(a, b)) # 最大公约数: 6
print(math.lcm(a, b)) # 最小公倍数: 36 (Python 3.9+)
print(math.factorial(5)) # 阶乘 (5!): 120
print(math.isqrt(20)) # 整数开平方: 4 (相当于 int(sqrt(20)))
# 2. 取整与数值处理
x = 3.14
print(math.ceil(x)) # 向上取整: 4
print(math.floor(x)) # 向下取整: 3
print(math.trunc(-3.9)) # 截断取整: -3 (直接去掉小数)
print(math.isclose(0.1+0.2, 0.3)) # 浮点数等价判断: True (解决精度问题)
# 3. 指数与对数
print(math.sqrt(16)) # 开平方: 4.0
print(math.log(math.e)) # 自然对数 ln(e): 1.0
print(math.log2(8)) # 以2为底: 3.0 (求二进制位数常用)
print(math.log10(100)) # 以10为底: 2.0
# 4. 组合数学 (Python 3.8+)
n, k = 5, 2
print(math.comb(n, k)) # 组合数 C(5,2): 10
print(math.perm(n, k)) # 排列数 A(5,2): 20
# 5. 几何与三角函数
print(math.pi) # π: 3.141592653589793
print(math.degrees(math.pi)) # 弧度转角度: 180.0
print(math.radians(90)) # 角度转弧度: 1.5707...
# 计算两点距离 (x1,y1) 到 (x2,y2)
print(math.dist((0, 0), (3, 4))) # 欧几里得距离: 5.0 (Python 3.8+)
# atan2 是竞赛神器:根据 (y, x) 返回弧度,能自动处理象限和除以 0 的情况
print(math.atan2(1, 1)) # 返回 pi/4
# 6. 特殊常数
inf = math.inf # 正无穷 (也可写 float('inf'))
nan = math.nan # 非数字 (Not a Number)
itertools 库
import itertools
# itertools 的特点:返回的是迭代器,不是 list
# 如果想直接查看结果,需要用 list() 转换
# 1. 全排列 permutations
a = [1, 2, 3]
print(list(itertools.permutations(a))) # 所有全排列: 3! 个
print(list(itertools.permutations(a, 2))) # 选 2 个排列: A(3,2)
# 常用于暴力枚举顺序,n 较大时会爆炸,竞赛中一般 n <= 8/9 才敢用
# 2. 组合 combinations
print(list(itertools.combinations(a, 2))) # 选 2 个组合: [(1, 2), (1, 3), (2, 3)]
# 组合不关心顺序,(1, 2) 和 (2, 1) 只算一种
# 3. 可重复组合 combinations_with_replacement
print(list(itertools.combinations_with_replacement(a, 2)))
# 输出: [(1,1), (1,2), (1,3), (2,2), (2,3), (3,3)]
# 4. 笛卡尔积 product
print(list(itertools.product([0, 1], repeat=3)))
# 输出所有 3 位 01 状态,常用于枚举二进制状态: 000 ~ 111
for state in itertools.product([0, 1], repeat=3):
print(state) # state 是 tuple,比如 (0, 1, 1)
# 多个集合做笛卡尔积
for x, y in itertools.product([1, 2], ["a", "b"]):
print(x, y) # (1,a), (1,b), (2,a), (2,b)
# 5. 累加 accumulate
nums = [1, 2, 3, 4]
print(list(itertools.accumulate(nums))) # 前缀和: [1, 3, 6, 10]
# 前缀最大值 / 最小值
print(list(itertools.accumulate(nums, max))) # [1, 2, 3, 4]
print(list(itertools.accumulate(nums, min))) # [1, 1, 1, 1]
# 6. 拼接多个可迭代对象 chain
a = [1, 2]
b = [3, 4]
c = [5]
print(list(itertools.chain(a, b, c))) # [1, 2, 3, 4, 5]
# 7. 分组 groupby
# 注意:groupby 只会把“连续相同”的元素分成一组,通常要先排序
nums = [1, 1, 2, 2, 2, 3, 1]
for key, group in itertools.groupby(nums):
print(key, list(group)) # 末尾的 1 会单独成组
nums.sort()
for key, group in itertools.groupby(nums):
cnt = len(list(group))
print(key, cnt) # 统计每个数出现次数
# 8. 无限迭代器 count / cycle / repeat
for i in itertools.count(1): # 从 1 开始无限递增
if i > 5:
break
print(i)
for x in itertools.repeat(7, 3): # 重复 7 三次
print(x)
# cycle 会无限循环,必须手动 break
cnt = 0
for x in itertools.cycle(["A", "B", "C"]):
if cnt == 5:
break
print(x)
cnt += 1
算法
import heapq
import math
import os
import sys
from collections import deque
import datetime
if os.path.exists("input.txt"):
sys.stdin=open("input.txt","r")
## sys.stdout=open("output.txt","w")
input = sys.stdin.readline
dijkstra
adj=[[]for _ in range(N)]
dist=[INF]*N
st=[False]*N
def dijkstra(start):
dist[start]=0
heap=[(0,start)]
while heap:
distance,u=heapq.heappop(heap)
if st[u]:
continue
st[u]=True
for v,w in adj[u]:
if dist[v]>distance+w:
dist[v]=distance+w
heapq.heappush(heap,(dist[v],v))
质数筛
primes=[]
st = [False] * 100
def get_primes(n):
for i in range(2,n+1):
if not st[i]:
primes.append(i)
for p in primes:
if p>n//i:
break
st[p*i]=True
if i%p==0:
break
prime算法
n=N
g=[[INF]*n for _ in range(n)]
def prime():
dist=[INF]*N
st=[False]*N
res=0
for _ in range(n):
t=-1
for j in range(1,n+1):
if not st[j] and (t==-1 or dist[t]>dist[j]):
j=t
if dist[t]==INF:
return INF
st[t]=True
res+=dist[t]
for j in range(1,n+1):
if not st[j]:
dist[j]=min(dist[j],g[t][j])
return res
floyd
d = [[INF] * (n + 1) for _ in range(n + 1)]
def floyd():
for k in range(1,n+1):
dk=d[k]
for i in range(1,n+1):
di=d[i]
dik=d[i][k]
if d[i][k]>=INF:
continue
for j in range(1,n+1):
di[j]=min(dik+dk[j],di[j])
并查集
def find(x):
root=x
while p[root]!=root:
root=p[root]
while p[x]!=root:
nx=p[x]
p[x]=root
x=nx
return root
可撤销并查集
import sys
input = sys.stdin.readline
n, m = map(int, input().split())
p = list(range(n + 1))
sz = [1] * (n + 1)
history = []
cnt = n
def find(x):
# 可撤销并查集不能路径压缩
while p[x] != x:
x = p[x]
return x
def merge(a, b):
global cnt
ra = find(a)
rb = find(b)
if ra == rb:
history.append((-1, -1, -1))
return
# 小集合挂到大集合下面
if sz[ra] > sz[rb]:
ra, rb = rb, ra
# 记录被挂的根、接收的根、接收根原来的大小
history.append((ra, rb, sz[rb]))
p[ra] = rb
sz[rb] += sz[ra]
cnt -= 1
def undo():
global cnt
if not history:
return
ra, rb, old_sz_rb = history.pop()
if ra == -1:
return
p[ra] = ra
sz[rb] = old_sz_rb
cnt += 1
ans = []
for _ in range(m):
op = input().split()
if op[0] == "1":
a, b = map(int, op[1:])
merge(a, b)
elif op[0] == "2":
a, b = map(int, op[1:])
ans.append("Yes" if find(a) == find(b) else "No")
else:
undo()
print("\n".join(ans))
拓扑排序
def add(x,y):
adj[x].append(y)
in_degree[x]+=1
n,m=map(int,input().split())
adj=[[] for _ in range(n+1)]
in_degree=[0]*(n+1)
for _ in range(m):
x,y=map(int,input().split())
add(x,y)
q=deque([i for i in range(1,n+1) if in_degree[i]==0])
res=[]
while q:
u=q.popleft()
res.append(u)
for v in adj[u]:
in_degree[v]-=1
if in_degree[v]==0:
q.append(v)
if len(res)==n:
print(*(res))
else:
print("-1")
import heapq
import math
import os
import sys
import datetime
if os.path.exists("input.txt"):
sys.stdin=open("input.txt","r")
## sys.stdout=open("output.txt","w")
input = sys.stdin.readline
N=100010
INF=float("inf")
adj=[[]for _ in range(N)]
dist=[INF]*N
st=[False]*N
def dijkstra(start):
dist[start]=0
heap=[(0,start)]
while heap:
distance,u=heapq.heappop(heap)
if st[u]:
continue
st[u]=True
for v,w in adj[u]:
if dist[v]>distance+w:
dist[v]=distance+w
heapq.heappush(heap,(dist[v],v))
primes=[]
st = [False] * 100
def get_primes(n):
for i in range(2,n+1):
if not st[i]:
primes.append(i)
for p in primes:
if p>n//i:
break
st[p*i]=True
if i%p==0:
break
n=N
g=[[INF]*n for _ in range(n)]
def prime():
dist=[INF]*N
st=[False]*N
res=0
for _ in range(n):
t=-1
for j in range(1,n+1):
if not st[j] and (t==-1 or dist[t]>dist[j]):
j=t
if dist[t]==INF:
return INF
st[t]=True
res+=dist[t]
for j in range(1,n+1):
if not st[j]:
dist[j]=min(dist[j],g[t][j])
return res
d = [[INF] * (n + 1) for _ in range(n + 1)]
def floyd():
for k in range(1,n+1):
dk=d[k]
for i in range(1,n+1):
di=d[i]
dik=d[i][k]
if d[i][k]>=INF:
continue
for j in range(1,n+1):
di[j]=min(dik+dk[j],di[j])
def find(x):
root=x
while p[root]!=root:
root=p[root]
while p[x]!=root:
nx=p[x]
p[x]=root
x=nx
return root
拓扑排序
def add(x,y):
adj[x].append(y)
in_degree[x]+=1
n,m=map(int,input().split())
adj=[[] for _ in range(n+1)]
in_degree=[0]*(n+1)
for _ in range(m):
x,y=map(int,input().split())
add(x,y)
q=deque([i for i in range(1,n+1) if in_degree[i]==0])
res=[]
while q:
u=q.popleft()
res.append(u)
for v in adj[u]:
in_degree[v]-=1
if in_degree[v]==0:
q.append(v)
if len(res)==n:
print(*(res))
else:
print("-1")

浙公网安备 33010602011771号