算法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 参数(布尔值,决定升序还是降序)。

指定排序范围

  1. 只对部分范围排序,并接回原列表

这是最常用的做法。以取出需要排序的部分,排序后再用切片赋值的方式把它们放回去。

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]
  1. 使用 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")
posted @ 2026-04-11 23:48  r_0xy  阅读(30)  评论(0)    收藏  举报