![](https://img-blog.csdnimg.cn/20190918140213434.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
算法笔记
文章平均质量分 50
笔记,仅供参考
shi_zi_183
这个作者很懒,什么都没留下…
展开
-
归并排序详解
归并排序排序的概念排序是将一批(组)任意次序的记录重新排列成按关键字有序的记录序列的过程。注意:首先需要打破僵化思维,排序的关键字可以指定多个,’有序‘的概念也是可以指定的,不只有递增或递减,排序的元素也不只有数字,任何可区分的元素都可以进行排序,因此排序算法会频繁的出现在各类算法中,不同的排序算法带来的思想常常是解决不同问题的突破点。关键概念归并:是指将两个或两个以上的有序序列合并成一个有序序列。这里考虑一下一次归并的时间复杂度: 朴素考虑:如果我们将两个有序序列拼接在一起,然后得到的新序列原创 2021-01-22 22:21:27 · 238 阅读 · 0 评论 -
KMP算法
KMP算法简介KMP 算法是 D.E.Knuth、J,H,Morris 和 V.R.Pratt 三位神人共同提出的,称之为 Knuth-Morria-Pratt 算法,简称 KMP 算法。该算法相对于 Brute-Force(暴力)算法有比较大的改进,主要是消除了主串指针的回溯,从而使算法效率有了某种程度的提高。原理KMP算法对朴素算法的优化在于通过利用目标字符串的性质(某些段前缀与后缀相同)来减少了指针的回溯,从而减少运算。于是KMP最重要和难理解的部分就是如何求解目标字符串的前缀和后缀相同的原创 2020-12-22 12:37:45 · 164 阅读 · 0 评论 -
关于的整数划分讨论(考虑顺序与不考虑顺序)
关于整数划分的讨论整数划分问一个整数有多少种划分为整数之和的组合。例如:4=1+1+1+14=1+1+1+14=1+1+1+14=2+1+1,4=2+24=2+1+1 ,4=2+24=2+1+1,4=2+24=3+14=3+14=3+14=44=44=4对于这个问题需要使用动态规划来解决首先定义dp数组我们定义dp[n][m]dp[n][m]dp[n][m]是数n的不超过m的划分组合数例如:dp[4][2]=3dp[4][2]=3dp[4][2]=3,其中包含4=1+1+1+14=1+1原创 2020-11-16 21:33:40 · 446 阅读 · 0 评论 -
Manacher算法_回文串
Manacher算法Manacher算法通常用于计算一个字符串的最长回文子串,注意是子串而不是子序列,子序列有另一种算法。对于最长回文子串的朴素方法是通过枚举左右两端的位置进而枚举所有的可能子串,然后在左右比较判断是否为回文,对一个子串进行判断的时间复杂度是O(n)O(n)O(n),枚举的子串一共有n2n^2n2个,所以总复杂度是O(n3)O(n^3)O(n3)。对此我有一步简单的优化,我们不再通过两端来枚举子串而是通过中心位置与半径长度来枚举,这样我们可以节省一些无意义的运算。例如123452112原创 2020-11-02 20:48:03 · 151 阅读 · 0 评论 -
可持续化线段树
可持久化线段树可持久化线段树是基本线段树的一个简单扩展,是使用函数式编程思想的线段树,它的特点是支持询问历史版本,并且利用历史版本之间的共用数据来减少时间与空间的消耗。可持续化线段树的基本特点是多棵线段树,根据具体情况,没棵线段树可以表示不同的含义。例如在区间第k大问题中,第i棵树是区间[1,i]的线段树。可持久化线段树用到的技术包括:前缀和思想+共用点+离散化+权值线段树(可以相减)+动态开点。区间第k大问题主席树 洛谷 P3834题目描述:给定n个整数构成的序列a,队指定的闭区间[L, R]原创 2020-10-29 12:31:34 · 944 阅读 · 0 评论 -
图论:最小生成树
最小生成树总结Prim算法prim算法是主要解决与边数无关和顶点数相关的算法,适合求解稠密图的最小生成树。算法的时间复杂度为O(n2)O(n^2)O(n2),空间复杂度是O(n2)O(n^2)O(n2)。步骤1.从任意一个顶点开始构造生成树,用一个数组记录哪些顶点已经加入了生成树。2.用数组dist记录生成树到各顶点的距离。3.从数组dist中选出离生成树最近的顶点(假设为j)加入到生成树中。再以j为中间点,更新生成树到每一个非树顶点的距离(松弛)。4.重复第三步,直到生成树有n个顶点为止。原创 2020-10-21 22:34:03 · 436 阅读 · 0 评论 -
图论:最短路径_SPFA算法
SPFA算法SPFA算法是使用队列优化的Bellman-Ford算法,求单源最短路径的一种算法。SPFA算法进行了两种优化,但在最坏的情况下效果不佳,与不优化时相同。效率与Bellman-Ford算法相同,但SPFA算法以点展开,Bellman-Ford算法以边展开。Bellman-Ford算法比SPFA算法好写很多。实现方法建立一个队列,初始时队列里只有起始点,在建立一个表格记录起始点到所有点的最短路径(该表格的起始值要赋为极大值,该点到他本身的路径赋为0)。然后执行松弛操作,用队列里有的点去刷新原创 2020-10-19 22:55:41 · 156 阅读 · 0 评论 -
图论:最短路径_Bellman-Ford算法
Bellman-Ford算法问题我们假设有一有向图G=(V,E,W)G=(V,E,W)G=(V,E,W),其中的每条边ei,j:={vi,vj}e_{i,j}:=\{v_i,v_j\}ei,j:={vi,vj}的权值为一个非负的实数wi,j(ei,j)w_{i,j}(e_{i,j})wi,j(ei,j),该权值表示从顶点viv_ivi到顶点vjv_jvj的距离。并设一单源点s∈Vs\in Vs∈V。我们需要找出从源点S出发,到V−{s}V -\{s\}V−{s}中的所有节点的最短路径。D原创 2020-10-15 21:36:51 · 309 阅读 · 0 评论 -
图论:最短路径算法_Floyd算法
Floyd算法floyd算法是一个经典的动态规划算法,他又被称为插电法。Floyd算法是一种利用动态规划的思想寻找给定的加权(可以有负权)图中多源点之间最短路径的算法,算法目标是寻找从点i到点j的最短路径。dp数组与递推式既然是动态规划那么一定有递推式,我们发现i−>ji->ji−>j的路径不外乎两种:1.直接i−>ji->ji−>j中间不经过任何点。2.i−>k−>ji->k->ji−>k−>j经过了一些节点k。k可能原创 2020-10-15 09:45:32 · 388 阅读 · 0 评论 -
图论:最短路径算法_Dijkstra算法
最短路径就像排序算法,最短路径问题真的是值得重复研究的。(主要是我半年没看都忘了)之前总结过一次,就只是罗列了一些之前写的程序,这次想深入讨论一下。(当然也不一定能讨论清楚)迪杰斯特拉算法一说到最短路径那第一个一定是迪杰斯特拉算法。Dijkstra算法通过类似广度优先的策略来解决带权图的单源最短路径(无负权边,无环)Dijkstra算法运用了贪心的思想,算法只会着眼于当下的最优情况,一旦选择路径后无法更改,所以无法解决负权边,也不能结束环的死循环。问题我们假设有一有向图G=(V,E,W)G=(原创 2020-10-14 23:06:16 · 357 阅读 · 0 评论 -
矩阵压缩储存
矩阵压缩储存矩阵是许多科学与工程计算问题中研究的数学对象。我们感兴趣的不是矩阵本身而是如何储存矩阵的元,从而使矩阵的各种运算能够有效地进行。矩阵压缩需要矩阵具有某些相同的元素或者零元素,假若值相同的元素或者零元素在矩阵中的分布具有一定规律,则我们称此类矩阵为特殊矩阵;反之,成为稀疏矩阵。下面分别讨论他们的压缩储存。特殊矩阵对称矩阵若n阶矩阵A中的元满足aij=aji 1≤i,j≤na_{ij}=a_{ji}\ 1\le i,j\le naij=aji 1≤i,j≤n则称为n原创 2020-10-01 01:04:14 · 441 阅读 · 0 评论 -
莫队算法
莫队算法基础莫队算法莫队算法=离线+暴力+分块离线与在线的概念。在线是交互式的,一问一答;如果前面的答案用于后面的提问,称为“强制在线”。离线是非交互的,一次性读取所有问题,然后一起回答,"记录所有步,回头再做”。基础的莫队算法是一种离线算法,它通常用于不修改只查询的一类区间问题,复杂度O(nn)O(n\sqrt{n})O(nn) ,没有在线算法线段树或树状数组好,但是编码很简单。下面是一道莫队模板题。HH项链 洛谷 1972题目描述:给定一个数量,询问某个区间内不同的数有多少个。输入:第一转载 2020-09-19 23:04:31 · 347 阅读 · 0 评论 -
静态区间查询——RMQ算法
RMQ算法问题是给一个数组,其中有N的数字,给多个询问,要求给出一个区间内的最大值。如果每次暴力法,每个询问都遍历那么时间复杂度是O(n2)O(n^2)O(n2)。这样重复运算太多了,我们如果用树状数组或区间树每次询问的时间复杂度是O(logn)O(logn)O(logn),树状数组和区间树是设计的便于修改的,那有没有更快的,有!,RMQ算法每次询问的时间复杂度是O(1)O(1)O(1)(需要注意的是RMQ只适用于静态区间最值的查询,限制很大。)RMQ算法一般用较长时间做预处理,时间复杂度为O(nlog原创 2020-09-19 12:38:23 · 252 阅读 · 0 评论 -
数据结构——二叉排序树与平衡二叉树
二叉排序树二叉排序树或是一棵空树,或着是具有以下性质的二叉树:(1)若左子树不空,则左子树上的所有节点值均小于他的根节点值。(2)若右子树不空,则右子树上的所有节点值均大于他的根节点值。(3)它的左右子树也分别为二叉树。如图就是一个二叉排序树。查找,二叉排序树又叫二叉查找树,查找方法与次优二叉树相同,将查找值与当前节点比较若相等,则查找成功,若大了则继续在右子树寻找,小了则继续在左子树寻找。Bitree* SearchBST(Bitree* T,int key){ if((!T)||T-原创 2020-09-16 08:38:32 · 1099 阅读 · 0 评论 -
插头dp
插头dp之前在讲状压dp时还没有了解过插头dp,但状压的最后一道例题已经和插头dp很像了,这节就来解决一个插头dp的入门问题。插头dp学习之前需要掌握或了解的东西:状压dp,哈希表,状压用来压缩一些局面,但可能出现的情况很多导致状压后的数很大,这时候就可以使用哈希表来仅存放已出现的局面,避免开辟太大的数组。插头dp有几个关键词,当关键词出现时可以向这方面考虑:超小数据范围,网格图,连通性。还需要理解一些抽象的定义:插头一个格子以某种方式向另一个格子相连,相连的位置叫插头,具体的类似拼图的凹槽与凸原创 2020-09-14 20:58:17 · 757 阅读 · 0 评论 -
分块算法
分块分块概念回顾“区间”问题,前面给出了暴力法,树状数组,线段树等方法。给定一个n个数的数列,做m次区间修改和区间查询。暴力法正能解决小规模问题,但是代码简单;树状数组和线段树都使用了二分的思想,但是代码复杂。这节的分块算法介于两者之间,...原创 2020-09-12 09:57:59 · 631 阅读 · 1 评论 -
线段树
线段树线段树概念线段树和树状数组都是解决区间问题的数据结构,线段树的两个经典问题:区间求和,区间最值。(1)区间最值:1)求最值:给定i, j ≤ n,求区间[i, j]内的最值。2)修改元素:给定k和x,把第k个元素a[k]改成x。如果用普通数组存储数列,上面2个操作,求最值的复杂度是O(n),修改是O(1)。如果有m次“修改元素+查询最值”,那么总复杂度是O(mn)。如果m和n比较大,例如105,那么整个程序的复杂度是1010数量级,这个复杂度在算法竞赛中是不可接受的。(2)区间求和:给原创 2020-09-03 20:22:18 · 918 阅读 · 0 评论 -
树状数组的应用
树状数组的应用偏序问题逆序对 洛谷 1908题目描述:对于给定的一段正整数序列,逆序对就是序列中ai > aj且i < j的有序对。计算一段正整数序列中逆序对的数目。序列中可能有重复数字。输入格式:第一行,一个数 n,表示序列中有 n个数。第二行n个数,表示给定的序列。序列中每个数字不超过 109。n <= 5×105。输出格式:输出序列中逆序对的数目。输入样例:65 4 2 6 3 1输出样例:11题解:直接暴力循环O(n2),利用树状数组O(nlogn)。用树原创 2020-08-31 17:16:58 · 120 阅读 · 0 评论 -
树状数组——高级数据结构
树状数组(1)序言树状数组与线段树都是为了解决一个问题就是:高效的查询和维护前缀和(区间和)。前缀和就是给出一个数组和n,求出这个数组前n个数的和,区间和可以通过前缀和求出,例如[i,j]的区间和等于j的前缀和减去i的前缀和。如果a数组是静态的那前缀和很简单,一次遍历就可以求出前缀和数组时间复杂度0(N),以后每次查询时间复杂度都是0(1)。但如果数组是动态变化的,例如改变了a[k]的值那么k之后的前缀和都需要从新求。所以如果每次查询前数据都会有所改变那么查询一次的时间复杂度就是0(N)。有两种原创 2020-08-23 08:46:26 · 232 阅读 · 0 评论 -
树上倍增LCA
树上倍增LCALCA:最近公共祖先朴素思想求LCA,有x,y两点,x、y有不同的深度,depth[x]、depth[y]。首先取x,y的深度最大的点一步一步往上追溯直到x与y的深度相同,再x与y共同追溯直到发现到相同的一点,这一点就是最近公共祖先。但显然这种一步一步非常慢,所以就要用到倍增求LCA倍增是指每次跳着走,每次跳2的i次方的点。对于跳点的定位需要一个数组f[x][i]x是点的下标,i是x的第2的x次方祖先,i为零时f[x][0]就是x的父亲。用一次dfs就可以求出f数组。同朴素的步骤一样原创 2020-08-21 13:44:59 · 348 阅读 · 0 评论 -
差分约束系统
差分约束系统定义:全部都由两个未知量的差小于等于一个常量的组成的不等式组叫差分约束系统。这样的不等式要么无解,要么有无数解。且如果有一组解为{x1,x2。。。xn},因为所有数都加上一个定值他们的差不会变所以{x1+k,x2+k。。。xn+k}也为解,因为k可以任意取,所以解有无数个。差分约束系统的解法可以利用最短路径的三角公式,对于u->v来说,d[v]<=d[u]+w[u][v],也可以写为d[v]-d[u]<=w[u][v]。 其中d(u)和d(v)是从源点分别到点u和点v的原创 2020-08-20 19:21:51 · 194 阅读 · 0 评论 -
树的分治
树的分治树的分治分为两种:点分治、边分治。点分治:点分治就是每次找到重心,然后把重心去掉,对分成的每两棵树之间分别统计路径信息(以重心的每个相邻点为根,遍历整棵子树即可得到这个根到每个结点的统计信息),就可以知道包含这个重心的所有路径的信息,然后对于剩下的路径就是在子树里面进行同样的操作了,直到只剩一个点为止(注意这一个点所构成的路径有时也要处理一下)。边分治:边分治就是每次找到一条边,使得删掉这条边后分成的两棵子树大小尽可能平均,然后以删掉的边的两端点为根,分别统计根到两棵树中的每个结点的路径信息,原创 2020-08-20 12:12:08 · 676 阅读 · 0 评论 -
树状dp的应用
树状dp的应用树的最大独立集、重心、最长点对是常见的问题树的重心树的重心也叫树的质心。找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。例题:黑帮老大题目描述: 城里有一个黑手党组织。把黑手党的人员关系用一棵树来描述,教父是树的根,每个结点是一个黑手党徒。为了保密,每人只和他的父结点和他的子结点联系。警察知道哪些人互相来往,但是不知他们的关系。警察想找出谁是教父。 警察假设教父是一个聪明人:教父懂得制衡手下的权力,所以他直属的的几原创 2020-08-19 19:32:32 · 167 阅读 · 0 评论 -
树状dp
树状dp在树结构上做dp,常见的题型是:给出一棵树,让你实现最小代价或找到最大收益。树这种结构本身具有“子结构”具有递归性,所以非常适合进行dp。基于树的解题步骤一般是:先把树转为有根树(如果是几个互不连通的树,就加一个虚拟根,它连接所有孤立的树),然后在树上做DFS,递归到最底层的叶子节点,再一层层返回信息更新至根结点。显然,树上的DP所操作的就是这一层层返回的信息。不同的题目需要灵活设计不同的DP状态和转移方程。树形dp的基本操作先看一个简单的入门题。通过这一题,了解树的存储,以及如何在树上设原创 2020-08-18 17:31:11 · 1951 阅读 · 1 评论 -
状态压缩dp
状态压缩dp引子:最短哈密顿路径时间限制:3s。题目描述:给定一个有权无向图,包括n个点,标记为0 ~ n-1,以及连接n个点的边,求从起点0到终点n-1的最短路径。要求必须经过所有点,而且只经过一次。1 ≤ n ≤ 20。输入格式:第一行输入整数n。接下来n行每行n个整数,其中第i行第j个整数表示点i到j的距离(记为a[i, j])。0 ≤ a[i, j] ≤ 10^7对于任意的x, y, z,数据保证 a[x, x]=0,a[x, y]=a[y, x] 并且 a[x, y]+a[y, z]&g原创 2020-08-18 10:50:35 · 235 阅读 · 0 评论 -
区间dp
区间dp石子合并题目描述:有n堆石子排成一排,每堆石子有一定的数量。将n堆石子并成为一堆,每次只能合并相邻的两堆石子,合并的花费为这两堆石子的总数。经过n-1次合并后成为一堆,求总的最小花费。输入:第一行是整数n,表示有n堆石子。第二行有n个数,分别表示这n堆石子的数目。输出:总的最小花费。输入样例:32 4 5输出样例:17提示:样例的计算过程是:第一次合并2+4=6;第二次合并6+5=11;总花费6+11=17。for(int i=1; i<=n; i++) dp[原创 2020-08-17 18:33:31 · 139 阅读 · 0 评论 -
数位dp
数位dp数位dp是一种计数用的dp,一般就是要统计一个区间[le,ri]内满足一些条件数的个数。所谓数位dp,字面意思就是在数位上进行dp咯。数位还算是比较好听的名字,数位的含义:一个数有个位、十位、百位、千位…数的每一位就是数位啦!之所以要引入数位的概念完全就是为了dp。数位dp的实质就是换一种暴力枚举的方式,使得新的枚举方式满足dp的性质,然后记忆化就可以了。windy数不含前导零且相邻两个数字之差至少为 2 的正整数被称为 windy 数。求a,b之间有几个windy数输入格式输入只有一行原创 2020-08-17 11:44:25 · 292 阅读 · 0 评论 -
排序算法(3)
排序算法(3)归并排序算法描述:将待排序的元素序列分为两个长度相等的子序列,对每个子序列进行排序,然后将他们合并成一个序列,合并两个子序列的过程称为二路归并.#include<stdio.h>#include<stdlib.h>#include<malloc.h>#include<string.h>#include<assert.h>//归并void MergeData(int *arr,int left,int mid,int转载 2020-08-12 08:09:28 · 93 阅读 · 0 评论 -
排序算法(2)
排序算法(2)希尔排序希尔(Shell)排序又称为缩小增量排序,它是一种插入排序。它是直接插入排序算法的一种威力加强版。该方法因DL.Shell于1959年提出而得名。#include<iostream>using namespace std;int a[10] = { 9,8,7,6,5,4,3,2,1,0 };void shell_sort(int size){ int gap = size >> 1; int i, key, end; while (ga原创 2020-08-11 09:04:46 · 74 阅读 · 0 评论 -
排序算法(1)
排序算法(1)冒泡排序冒泡排序是最简单的排序方法,但是时间复杂度也很高。算法描述:比较两个相邻的元素,如果升序的话,前面的比后面的大,就交换,这样一轮下来,就会找到这组数据中最大的元素,然后抛开这个元素继续重复上述步骤.直到排完为止。#include<iostream>using namespace std;int a[10] = { 9,8,7,6,5,4,3,2,1,0 };const int max = 10;int main(){ for (int i = 0;原创 2020-08-10 20:45:31 · 101 阅读 · 0 评论 -
最短路径算法
最短路径算法Dijkstra算法_单源最短路径Dijkstra算法算法用于在非负加权图中寻找最短路径;算法思路,从起点辐射式的寻找路径(进入电脑视野的路径及通过已知最短路径的点可到达的点),每次计算后最短的路径可确认我这个点的最短路径,反复多处直至发现终点的最短路径;int dist[10], prev[10], v = 1, s[10];dist【】用于记录最短路径;prev【】用于记录到达此点最短路径的前一个点;s【】用于记录此点是否已找到最短路径;int dist[原创 2020-08-08 06:53:07 · 160 阅读 · 0 评论 -
EF算法中的最短长度增值算法(MPLA)
EF算法中的最短长度增值算法(MPLA)(1)初始化一条容量为0的流f和剩余网络R,第一个剩余网络为原图G,每条边的剩余容量初始化为每条边的初始容量r(u,v)=c(u, v)。(2)在剩余网络R中寻找增广路径P,取增广路径P中边的剩余容量r最小值作为流的增量修改剩余网络(正向边,反向边都修改)在剩余网络里搜索有s到t的最短路径视为增广路径.(3)重复(2)直到找不到一条增广路径。增广路径如果一个可行流不是最大流,那么当前网络中一定存在一条增广路经。从源点S到汇点T的一条路径中,如果边(u,v原创 2020-07-30 06:50:06 · 806 阅读 · 0 评论 -
数据结构——静态查找表
静态查找表顺序查找表顺序表与线性链表都可以表示静态查找表。两者的实现静态查找表相似,这里以顺序表为例。顺序查找就是从表中最后一个记录开始,逐个进行记录关键字与给定值的比较,若某个记录的关键字和给定值比较相等,则查找成功,反之失败。对于顺序查询有一种技巧可以优化效率。查找之前先将key赋值给elem[0],搜索从后向前搜索,这样可以免去每次循环都要检查整个表是否搜索完毕,这样时间可以减少一半。当然监视哨也可以放在表尾。有序表的查找无序表可以使用顺序查找,有序表除此以外还可以使用折半查找。折半查原创 2020-09-11 19:02:12 · 957 阅读 · 0 评论 -
数据结构——哈希表
哈希表序言哈希表又称散列表。对于一般的数据结构,记录在结构中的相对位置都是随机的,和记录的关键字无关,因此要想找到数据在数据结构中的相对位置需要进行一系列和关键字的”比较”。例如顺序结构的比较的结果为==或!=,折半查找,二叉树排序树查找和B–树查找时比较的结果为<或>等等。(查找的效率依赖于查找过程中所进行的比较次数)当然最理想的情况下,我们希望一次存取就可以查找所有元素,这就需要在每个储存位置与它的关键字之间建立一个对应关系f,使其一一对应。哈希函数哈希函数的设定非常灵活,他是原创 2020-09-10 17:21:14 · 198 阅读 · 0 评论