跟着B站大佬的视频学习各类算法,整理了一份【从入门到省选】的题单。(鉴于个人水平有限,可能会变成《从入门到放弃》(T v T))。分享给有同样需求的你。
D - 图论
【Dijkstra】
| 题目来源 |
标题 |
难度 |
星级 |
考察算法 |
一句话思路总结 |
| 洛谷 |
P3371 单源最短路径(弱化版) |
普及 |
⭐⭐⭐ |
Dijkstra(堆优化) |
用优先队列维护当前最短距离节点,每次取出最小点进行松弛,时间复杂度 \(O(m \log n)\),空间复杂度 \(O(n+m)\) |
【Floyd】
| 题目来源 |
标题 |
难度 |
星级 |
考察算法 |
一句话思路总结 |
| 洛谷 |
B3647 Floyd |
普及 |
⭐⭐ |
Floyd-Warshall |
使用动态规划思想,通过三重循环枚举中间节点 \(k\) 来松弛所有点对 \((i,j)\) 的距离,最终得到全源最短路径,时间复杂度 \(O(n^3)\),空间复杂度 \(O(n^2)\) |
| 洛谷 |
P6175 无向图的最小环问题 |
普及 |
⭐⭐⭐ |
Floyd |
在 Floyd 更新过程中,利用未经过中间节点 \(k\) 的最短路 dist[i][j] 与两条直接边构成环,枚举所有 \(i<j<k\) 取最小值,时间复杂度 \(O(n^3)\),空间复杂度 \(O(n^2)\) |
【Johnson】
| 题目来源 |
标题 |
难度 |
星级 |
考察算法 |
一句话思路总结 |
| 洛谷 |
P5905 全源最短路(Johnson) |
提高 |
⭐⭐⭐⭐ |
Johnson + SPFA + Dijkstra |
用 SPFA 求势函数并检测负环,重赋权使边权非负后对每个点做 Dijkstra,还原真实距离,时间复杂度 \(O(n m \log n)\),空间复杂度 \(O(n+m)\) |
【SPFA】
| 题目来源 |
标题 |
难度 |
星级 |
考察算法 |
一句话思路总结 |
| 洛谷 |
P3385 负环 |
普及 |
⭐⭐⭐ |
SPFA(判负环) |
使用 SPFA 记录每个节点被松弛的次数,若某节点松弛次数达到 \(n\) 则说明存在负环;注意仅当该负环从顶点 1 可达时才输出 YES,时间复杂度 \(O(nm)\),空间复杂度 \(O(n+m)\) |
| 洛谷 |
P4779 单源最短路径(标准版) |
普及 |
⭐⭐⭐ |
Dijkstra(堆优化) |
用优先队列维护当前最短距离,每次取最小点松弛邻接边,直至所有点确定,时间复杂度 \(O(m \log n)\),空间复杂度 \(O(n+m)\) |
【生成树】
| 题目来源 |
标题 |
难度 |
星级 |
考察算法 |
一句话思路总结 |
| 洛谷 |
P3366 最小生成树 |
普及 |
⭐⭐⭐ |
最小生成树(Prim/Kruskal) |
使用 Kruskal 将边按权值排序,贪心加入不形成环的边直至连通;或使用 Prim 逐步扩展最近节点,判断图连通性,时间复杂度 \(O(M \log M)\),空间复杂度 \(O(N+M)\) |
【最近公共祖先】
| 题目来源 |
标题 |
难度 |
星级 |
考察算法 |
一句话思路总结 |
| 洛谷 |
P3379 最近公共祖先(LCA) |
普及 |
⭐⭐⭐ |
倍增法 / Tarjan离线 / 树链剖分 |
预处理每个节点的 \(2^k\) 级祖先,查询时先调深度再同步上跳,\(O(\log N)\) 回答每次询问;或使用 Tarjan 离线算法一次 DFS 处理所有查询,总复杂度 \(O(N+M)\);树链剖分通过链顶跳跃实现 \(O(\log N)\) 查询,空间 \(O(N)\) 或 \(O(N \log N)\) |
【树链剖分】
| 题目来源 |
标题 |
难度 |
星级 |
考察算法 |
一句话思路总结 |
| 洛谷 |
P3384 重链剖分 |
提高+ |
⭐⭐⭐⭐ |
树链剖分 + 线段树 |
用树链剖分将路径和子树转化为连续区间,用线段树维护区间加和区间和,支持路径/子树加与求和,时间复杂度 \(O((N+M)\log^2 N)\),空间复杂度 \(O(N)\) |
【强连通分量】
| 题目来源 |
标题 |
难度 |
星级 |
考察算法 |
一句话思路总结 |
| 洛谷 |
P2341 受欢迎的牛 |
普及+ |
⭐⭐⭐⭐ |
Tarjan强连通分量 + 缩点 |
用Tarjan求强连通分量并缩点为DAG,统计各SCC出度,若恰好有1个出度为0的SCC则其大小即为明星牛数量,否则为0,时间复杂度 \(O(N+M)\),空间复杂度 \(O(N+M)\) |
| 洛谷 |
P2812 校园网络 |
提高+ |
⭐⭐⭐⭐⭐ |
Tarjan + 缩点 |
用 Tarjan 求出强连通分量并缩点,统计入度和出度为 0 的分量数,第一问为入度 0 的数量,第二问为 max(入度0, 出度0)(单分量时 0),时间复杂度 \(O(n+m)\),空间复杂度 \(O(n+m)\) |
| 洛谷 |
P3387 缩点 |
普及+ |
⭐⭐⭐ |
Tarjan + 缩点 + DAG DP |
用 Tarjan 求强连通分量并缩点,将每个分量的点权累加,在 DAG 上按逆拓扑序 DP 求最长路径和,时间复杂度 \(O(n+m)\),空间复杂度 \(O(n+m)\) |
| 洛谷 |
P3388 割点 |
普及+ |
⭐⭐⭐⭐ |
Tarjan / 割点判定 |
DFS 遍历无向图维护每个节点的 dfn(时间戳)和 low(能回溯到的最早祖先),对于非根节点若存在子节点 \(y\) 满足 low[y] >= dfn[x] 则 \(x\) 是割点,对于根节点需有两个以上独立子树才是割点,最终统计并输出所有割点。 |
【双连通分量】
| 题目来源 |
标题 |
难度 |
星级 |
考察算法 |
一句话思路总结 |
| 洛谷 |
P1656 炸铁路 |
普及- |
⭐⭐⭐ |
Tarjan / 桥(割边)判定 |
DFS 遍历无向图维护每个节点的 dfn(时间戳)和 low(能回溯到的最小 dfn),对于树边 \((x,y)\) 若 low[y] > dfn[x] 则该边是桥(删除后 \(y\) 的子树与图其余部分断开),用 j != (in_edg ^ 1) 避免走回头路,最后将所有桥按端点排序输出。 |
| 洛谷 |
P2860 Redundant Paths |
提高+ |
⭐⭐⭐⭐⭐ |
边双连通分量(Tarjan)/ 缩点 |
用 Tarjan 算法标记所有桥并求出边双连通分量缩点,缩点后得到一棵树,统计树中度数为 \(1\) 的叶子节点数量 \(leaf\),最少需要添加 \((leaf+1)/2\) 条新边将叶子两两配对连接,使图变为边双连通。 |
| 洛谷 |
P8435 点双连通分量 |
普及+ |
⭐⭐⭐⭐ |
Tarjan / 点双连通分量 |
DFS 遍历无向图维护 dfn 和 low,对于子节点 \(y\) 若 low[y] >= dfn[x] 则 \(x\) 是割点,此时从栈中弹出节点直到 \(y\) 并与 \(x\) 一起构成一个点双连通分量(割点会保留在栈中供后续分量复用),孤立节点单独成分量,最终输出所有分量。 |
【二分图】
| 题目来源 |
标题 |
难度 |
星级 |
考察算法 |
一句话思路总结 |
| 洛谷 |
P3386 二分图最大匹配 |
普及+ |
⭐⭐⭐ |
匈牙利算法(增广路) |
用匈牙利算法对每个左部点尝试找增广路,若能找到则匹配数加 1,时间复杂度 \(O(n \cdot e)\),空间复杂度 \(O(n+m+e)\) |
| 洛谷 |
P6577 二分图最大完美匹配 |
省选 |
⭐⭐⭐⭐⭐ |
KM 算法(BFS 版) |
利用可行顶标将问题转化为相等子图上的完美匹配,通过 BFS 增广和顶标调整逐步扩展相等子图,最终求得最大权匹配,时间复杂度 \(O(n^3)\),空间复杂度 \(O(n^2)\) |
【网络流】
| 题目来源 |
标题 |
难度 |
星级 |
考察算法 |
一句话思路总结 |
| 洛谷 |
P3376 网络最大流 |
提高+ |
⭐⭐⭐⭐⭐ |
Dinic / EK |
利用残量网络和 BFS/DFS 反复寻找增广路径,每次增加瓶颈流量,直至无增广路,得到最大流,Dinic 平均复杂度 \(O(V^2 E)\),空间 \(O(V+E)\) |
【费用流】
| 题目来源 |
标题 |
难度 |
星级 |
考察算法 |
一句话思路总结 |
| 洛谷 |
P3381 最小费用最大流 |
提高+ |
⭐⭐⭐⭐⭐ |
SPFA + EK(费用流) |
用 SPFA 在残量网络上按费用找最短增广路,沿路增广并更新残量网络,重复直至无增广路,得到最大流及最小费用,时间复杂度 \(O(F \cdot E \cdot V)\),空间复杂度 \(O(V+E)\) |
【2-SAT】
| 题目来源 |
标题 |
难度 |
星级 |
考察算法 |
一句话思路总结 |
| 洛谷 |
P4782 2-SAT |
提高+ |
⭐⭐⭐⭐ |
Tarjan + 2-SAT |
将每个变量拆为真假节点,子句转蕴含边,用 Tarjan 求 SCC 判断矛盾,按 SCC 逆拓扑序赋值,时间复杂度 \(O(n+m)\),空间复杂度 \(O(n+m)\) |
E - 动态规划
【树形DP】
| 题目来源 |
标题 |
难度 |
星级 |
考察算法 |
一句话思路总结 |
| 洛谷 |
B4016 树的直径 |
普及 |
⭐⭐ |
DFS / BFS |
两次 DFS:第一次从任意点找到最远端点,第二次从该端点找到最远距离,即为树的直径,时间复杂度 \(O(n)\),空间复杂度 \(O(n)\) |
| 洛谷 |
AT_agc001_c Shorten Diameter |
普及+ |
⭐⭐⭐ |
枚举 + DFS |
枚举树的中心点或中心边,统计半径内能覆盖的最大节点数,\(K\) 为偶数时中心为点,奇数为边,答案 \(= N - 最大覆盖数\),时间复杂度 \(O(N^2)\),空间复杂度 \(O(N)\) |
| 洛谷 |
P2195 HXY造公园 |
普及+ |
⭐⭐⭐ |
并查集 + 树的直径 + 树形 DP |
预处理每个连通块的直径,合并时用公式 \(\max(d_1, d_2, \lceil d_1/2 \rceil + \lceil d_2/2 \rceil + 1)\) 更新新直径,查询时直接输出,时间复杂度 \(O(n + q \cdot \alpha(n))\),空间复杂度 \(O(n)\) |
| 洛谷 |
P2610 旅游 |
普及+ |
⭐⭐⭐ |
对偶树 + 树的直径 |
将三角剖分转化为对偶树,求树的直径(边数),答案 = 直径边数 + 1,时间复杂度 \(O(n \log n)\),空间复杂度 \(O(n)\) |
| 洛谷 |
P3304 直径 |
普及+ |
⭐⭐⭐⭐ |
树形 DP / 两次 DFS |
用两次 DFS 求直径并记录路径,标记主直径后,从路径节点向非直径方向 DFS,判断是否存在绕过该边的直径,从而确定公共边区间,时间复杂度 \(O(N)\),空间复杂度 \(O(N)\) |
| 洛谷 |
CF911F Tree Destruction |
提高+ |
⭐⭐⭐⭐ |
树的直径 + 贪心 |
先求直径并标记路径,非直径叶子与直径较远端点配对累加距离,最后依次删除直径上的点并累加,总答案最大,时间复杂度 \(O(n)\),空间复杂度 \(O(n)\) |
| 洛谷 |
P2491 消防 |
提高+ |
⭐⭐⭐⭐ |
树形 DP + 双指针 |
求直径后用双指针在直径上枚举长度不超过 \(s\) 的子路径,同时计算分支深度,取最小最大距离,时间复杂度 \(O(n)\),空间复杂度 \(O(n)\) |
| 洛谷 |
P4408 逃学的小孩 |
提高+ |
⭐⭐⭐⭐ |
树的直径 + 三次 DFS |
求直径 \(D\),再求每个点到直径两端距离较小值的最大值 \(E\),答案 \(= D + E\),时间复杂度 \(O(N)\),空间复杂度 \(O(N)\) |
| 洛谷 |
P3629 巡逻 |
省选 |
⭐⭐⭐⭐ |
树的直径 + 树形 DP |
先求直径 \(D_1\),\(K=1\) 时答案为 \(2(n-1)-D_1\);\(K=2\) 时在直径路径上标记边权为 \(-1\) 后做树形 DP 求最长链 \(D_2\),答案为 \(2(n-1)-D_1-D_2\),时间复杂度 \(O(n)\),空间复杂度 \(O(n)\) |