随笔分类 - 从0.5开始的算法学习记录
摘要:Dijkstra单源最短路堆优化算法 使用基于堆的优先队列,我们可以在进行松弛操作前对找边进行优化操作 时间复杂度为 \(O(m\log m)\) ,其中 \(m\) 为边的数量,优先队列找边的时间复杂度为\(O(\log m)\) 优先队列 默认为一个大根堆,即堆顶的元素的优先级最高,体现在某个变
阅读全文
摘要:NOI 1.6 12 题目描述 题目给出的 \(n\) 最大可以取到 \(100\) ,即计算 \(2^{100}\) ,明显是超过 long long 的 \(2^{63}-1\),所以需要使用高精度来计算幂次方的乘法 简单的高精度,即每次计算一个小整数乘上一个大整数 循环 \(n\) 次,每次对
阅读全文
摘要:快速幂笔记 快速幂,可以优化指数计算,将朴素的 \(O(n)\) 的时间复杂度优化到 \(O(\log n)\) 原理是,将幂通过二进制拆分,只需要计算拆分后的值,就能组合出完全幂的答案 举例如下:有 \(a^{14} = a^{1110_{(2)}} = a^{1*2^3}*a^{1*2^2}*a
阅读全文
摘要:Dijkstra单源最短路朴素算法(空间优化) 基于使用邻接表存储连接边的方法,可以有效的降低空间复杂度 在稀疏图(边的数量远小于顶点数量平方的图)中,邻接矩阵会大量占用无用的内存,导致Re,我们采用邻接表的办法,只存储存在的边,减少无关占用。相反,在稠密图(边的数量接近顶点数的平方的图)中,邻接表
阅读全文
摘要:Dijkstra单源最短路朴素算法 基于无优化的朴素算法,这里使用邻接矩阵的方法存储路径(空间复杂度高) Dijkstra单源最短路的算法原理如下: 从起始点s开始,每次依据贪心选取最近连通点且未被访问过的点,移动到该点上,更新最短路径,直到把所有点都访问完 初始化时,需要将s起始点到所有点的dis
阅读全文
摘要:多源最短路算法-Floyd 使用Floyd(弗洛伊德)算法,可以以 \(O(n^3)\) 的时间复杂度求出一张多源图的任意两点间的最短路径 一般采用邻接矩阵的方法来存储图: int g[N][N]; g[i][j] 其中,g[i][j]的意义为第i个节点到第j个节点的权重 我们需要对邻接矩阵进行路径
阅读全文
摘要:深入二分思想 二分在实际使用中常常会出现死循环的问题 这是因为我们对二分临界状态的不熟悉而导致的,这里介绍一种通用的分界想法: 整数二分: int l = begin - 1, r = end + 1; while (l + 1 != r) { int mid = l + r >> 1; if (j
阅读全文
摘要:树与图的存储与遍历(邻接表)笔记 树是一种特殊的图,树没有环且相互连通 图分为有向图和无向图,无向图可以转化为双向的有向图 图的存储 这里介绍一种存储图的方式:邻接表 数组模拟: int h[N], e[N], ne[N], idx; 把图的每个顶点都开一条单链表,记录在 h[N] 中,这个顶点能连
阅读全文
摘要:BFS入门笔记 BFS广度优先搜索,在处理问题时,优先考虑更多的机会,而不是像DFS那样优先走一条路,再回溯 BFS基于队列实现,目的是把可能的解放在同一层处理,即BFS队列中至多只有两层的解 考虑完前一层可能的解后,再考虑下一层的解。把当前解的后续解再放到队列尾部。 如上图中,BCDE处在同一层考
阅读全文
摘要:并查集笔记 并查集,一种可以高效处理连通区块问题的数据结构,可以优化集合合并操作,判断集合是否连通 它的原理可以简单概括为: 设置一个数组,把每个元素的祖先节点存在数组中,当要查询这个节点所在集合时,通过层层向上,最终找到一个最远祖先 初始化祖先数组时,我们将每个元素的祖先都设置为他自己,当我们查询
阅读全文
摘要:Trie树-字典树笔记 Trie树是一种高效的存储字符串的数据结构,它将多个字符串的前缀合并在一条边上,每次插入时,都判断当前的树上有无能够重合的前缀,如果没有就单独增加一个节点。通过合并前缀,可以做到快速查找已经优化空间的操作。 下面是使用数组模拟实现Trie树的部分代码: 我们首先定义一个二维数
阅读全文
摘要:DFS深度优先搜索-入门 笔记 DFS 依靠递归的思想,总是往更远的方向行进,直到达到边界,再返回到上一步考虑另外的方向 (递归-回溯) 递归实现指数型枚举 从 \(1\)~\(n\) 这 \(n\) 个整数中随机选取任意多个,输出所有可能的选择方案,即计算\(2^n\) 我们考虑有 \(n\) 个
阅读全文
摘要:双指针扩展-三指针笔记 在使用双指针维护一段序列时,可能会出现多个区间的情况,这时若是仅采用双指针移动,则会漏掉部分情况 可以再加入一个指针来,使两个指针维护一个子序列,使子序列和另外一个指针共同维护 这里以洛谷P1102为例: 我们需要对一段序列求满足条件的数对的数量,但由于序列中元素可以重复,所
阅读全文
摘要:最大子段和问题 ——————以洛谷P1115为例 最大子段和,顾名思义就是在一段数组中选取元素和最大的子段(或最小) 这里总结了动态更新的写法: int main() { int n, a, maxm, temp; scanf("%d", &n); for (int i = 0; i < n; i+
阅读全文
摘要:单调队列笔记 双端队列deque维护一个严格单调变化的组,可以称为一个单调队列 单调队列因为可以直接对组的两端进行操作,所以可以有效的降低时间复杂度 用单调队列来解决问题,一般是需要得到的某个范围内的最小值或最大值 这里以一道经典的单调队列的题目为例: 题目描述 有一个长为 \(n\) 的序列 \(
阅读全文
摘要:单调栈笔记 单调栈,顾名思义,就是把元素按照严格单调的顺序存在栈中(从「栈顶」到「栈底」) 可以加速查找数组中满足特定条件的数的过程,例如: 寻找左侧第一个比当前元素大的元素 寻找左侧第一个比当前元素小的元素 寻找右侧第一个比当前元素大的元素 寻找右侧第一个比当前元素小的元素 可以有效的将嵌套搜索的
阅读全文
摘要:单双链表(数组模拟)笔记 如题,我们要使用数组来模拟链表这个数据结构 区别于传统的结构体链表(动态链表): struct node { int value; struct node* next;//指向下一个节点的指针 }user_define_name;//调用链表的别称 数组模拟链表(静态链表)
阅读全文
摘要:一维离散化笔记 通俗来说,一维离散化就是把在无限空间中的有限元素映射到一个线性排列的区间中 举个实际的例子说明: 存在一个近似无限的空间 \([-10^9,10^9]\) ,我们需要对其中\(10^5\)个离散的元素进行操作 显然不可能对这个近似无限的区间进行\(10^5\)次遍历 所以需要把这\(
阅读全文
摘要:位运算笔记 对二进制数进行直接操作: 基础操作: 例: a=0000 1101; b=0011 0101; 与:a&b==0000 0101;//当两个数的第i位都为1时,a&b的第i位才为1 或:a|b==0011 1101;/*当两个数的第i位都为0时,a|b的第i位才为0 或者说两个数的第i位
阅读全文
摘要:双指针维护笔记 双指针特指两个指针共同维护一个数组: 从两端分别维护,从同一端点交叉维护 从两端分别维护: 例:快速排序,(从小到大排序) 在快速排序中,我们安排了两个指针从需要排序的数组的左右两端开始向中间移动 更新方式是,当 i 指针从左向右移动,j 指针从右向左移动时,若 i 的值大于 j 的
阅读全文