![](https://img-blog.csdnimg.cn/20201014180756757.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
算法模板整理
文章平均质量分 57
一些算法模板的整理,涉及到了ACM的常规模板算法,正在完善中。。。
一只特立独行的猫
转行web3中。。。
展开
-
最大流_FF思想_EK算法
原题链接poj 1273问题图论中有一个重要问题,假设有一个水管网图,每根水管都规定了一个可以流的方向,从v号结点到u号结点最大允许通过的水量为c(v,u),有一个源点s存储了无限多的水,有一个汇点可以存储无限多的水。问:从源点流向汇点的水流的最大速率是多少?思路采用经典的EK算法,时间复杂度为O(n*m^2)n为结点数,m为边数,虽然上界很高,但是一般情况很能到上界,一般的情况要好的多。四个概念,一个定理:网络流的概念和定理非常多,为了不混淆,先只讲两个会用到的定理。1.反向边:这个概原创 2021-09-07 18:32:26 · 528 阅读 · 0 评论 -
根据数据范围进行复杂度和算法猜测
n<=30指数级别:dfs+剪枝,状压dp,记忆化搜索n<=100O(n^3):floyd,组合背包dp,区间dpn<=1000O(n^2):计数dp,数位统计dp01背包,多重背包,完全背包,线性dp,区间dp(优化)O(n^2logn):dp+二分/堆n<=10000O(n*sqrt(n)):块状链表,约束之和,约数个数n<=100000O(nlogn),:各种sort,线段树,树状数组,set,map,heap(priority_queue<T.原创 2021-09-05 15:47:10 · 122 阅读 · 1 评论 -
贪心算法_排队不等式_绝对值不等式_推公式
文章目录排队不等式原题链接题目大意:思路:证明:代码:绝对值不等式原题链接题目大意:思路:证明:代码:推公式原题链接题目大意思路:证明:代码:排队不等式原题链接https://www.acwing.com/problem/content/915/题目大意:有 n 个人排队到 1 个水龙头处打水,第 i 个人装满水桶所需的时间是 ti,请问如何安排他们的打水顺序才能使所有人的等待时间之和最小?思路:从小到大排序,时间短的人先打水。证明:假设总时间为res=t1(n−1)+t2(n−2)+..原创 2021-09-05 11:30:23 · 409 阅读 · 0 评论 -
贪心算法_区间选点_区间分组_区间覆盖_huffman树
文章目录区间问题区间选点原题链接:题目大意:思路:证明:代码:区间分组原题链接:题目大意:思路:证明:代码:区间覆盖原题链接:题目大意:思路:代码:huffman树合并果子原题链接题目大意:思路:代码:区间问题区间选点原题链接:https://www.acwing.com/problem/content/907/题目大意:给定 N 个闭区间 [ai,bi],请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。输出选择的点的最小数量。位于区间端点上的点也算作区间内。思路:统计合原创 2021-09-04 16:53:26 · 288 阅读 · 0 评论 -
动态规划_计数类dp_数位统计dp_状态压缩dp_树形dp_记忆化搜索
计数类dp给定方案限制,统计某一种方案出现个数题目大意一个正整数 n 可以表示成若干个正整数之和,形如:n=n1+n2+…+nk,中 n1≥n2≥…≥nk,k≥1。我们将这样的一种表示称为正整数 n的一种划分。现在给定一个正整数 n,请你求出 n 共有多少种不同的划分方法。0<n<=1000思路通过完全背包解决。f(i,j)f(i,j)f(i,j)表示前iii个数放入容量为jjj的背包的组合数量。由于使用[1−(j−1)][1-(j-1)][1−(j−1)]凑jjj,所以一原创 2021-09-04 00:15:47 · 238 阅读 · 0 评论 -
动态规划_最长上升子序列plus_最短编辑距离
最长上升自序列plus题目大意给定一个长度为 N 的数列,求数值严格单调递增的子序列的长度最长是多少。0<N<100000;原题链接(相较于一般的O(n^2)复杂度的dp算法,由于扩大了数据量到1e5,所以要通过改进的办法来解决。)思路:设置一个ppp数组,p[i]p[i]p[i]表示长度为i的数组的结尾的数字。设置这个数组的原因是我们可以发现如下规律。对于任意一个递增子序列,如果在这个子序列后还存在一个比p[i]p[i]p[i]小,但是比p[i−1]p[i-1]p[i−1]大的原创 2021-09-01 22:19:07 · 158 阅读 · 0 评论 -
动态规划_线性动态规划,区间动态规划
模板题链接:数字三角形线性规划数字三角形思路:状态表示:arr[i][j]arr[i][j]arr[i][j]表示从(1,1)出发到(i,j)的最长路径。状态表示:arr[i][j]=max(arr[i−1][j−1],arr[i−1][j])+arr[i][j]arr[i][j]=max(arr[i-1][j-1],arr[i-1][j])+arr[i][j]arr[i][j]=max(arr[i−1][j−1],arr[i−1][j])+arr[i][j]代码:#include<i原创 2021-08-31 16:48:26 · 341 阅读 · 0 评论 -
动态规划_01背包_完全背包_多重背包_分组背包
目录动态规划问题结题思路:模板题链接:01背包思路:代码:完全背包思路:代码动态规划问题结题思路:模板题链接:01背包01背包思路:定义状态表示函数f(i,j):f(i,j):f(i,j):j空间大小的背包,在对(1 ~ i)号物品做出选择后,背包能装下的最大价值。所以产生了如下集合。在选择i号物品的情况下 : f(i,j)f(i,j)f(i,j)的值就为f(i−1,j−v[i])+w[i]f(i-1,j-v[i])+w[i]f(i−1,j−v[i])+w[i]在不选择i号物原创 2021-08-30 21:54:02 · 226 阅读 · 0 评论 -
最优博弈:Nim游戏,SG函数
公平组合游戏ICG(1)有两个玩家,游戏规则对两个玩家公平(2)游戏状态有限,能走的步数也是有限的(3)轮流走,当一个玩家不能走时游戏结束(4)游戏的局势不能区分玩家的身份,例如黑白棋就是不行的特征:给定初始局势,指定先手玩家,如果双方都采取最优策略,那么获胜者已经确定了,也就是说ICG问题存在必胜策略。常见ICG裸题:巴什游戏尼姆游戏图游戏和SG函数威佐夫游戏Nim游戏:有n堆石子,第i堆石子的数量是aia_iai, Alice和Bob可以从任意一堆石子中拿走任意石子。Al原创 2021-08-30 10:57:26 · 328 阅读 · 0 评论 -
二维线段树
线段树在用于一维空间中进行单点修改和区间查询非常具有优势,同样,在二维空间中线段树也可以实现该功能。可以查询区间和或者最小值。在面临多次单点修改和区间查询时,还是非常具有优势。如果需要进行区间修改和区间查询,那么就引入lazytag标记就可以实现优化。对比一下一维和二维线段树划分区间的思路:一维线段树划分区间思路:二维线段树划分区间的思路:大概就是上述思路,然后我们来看代码:#include<iostream>#define _1 node<<2 //第一象限#原创 2021-08-02 22:16:24 · 201 阅读 · 0 评论 -
位运算归纳(进阶)
为了便于描述,都是以例子的形式进行讲述。是本人在准备蓝桥杯国赛的时候,看视频的归纳,如果有不当之处,还望大家在评论区留言。1.列举排列情况如果有30个开关,每次可以随意开n个(0<n<31),要求得到所有的排列情况。(相当的暴力,一般情况下不推荐用,一般这种题用dp做,但是小规模简单题可以用这个方法,代码简单,写的快)解法:for(int i=0;i<1<<30;i++){ //pass; for(int j=0;j<30;j++){ //倒序输出所有排列原创 2021-06-14 09:25:44 · 120 阅读 · 0 评论 -
走迷宫_BFS
BFS的练手题,我顺便打印了路径。#include<iostream>#include<queue>using namespace std;const int N = 1e3 + 3;queue<pair<int, int > > q;//arr存放迷宫,p存放起点出发到x,y的路径长度int arr[N][N],p[N][N];int n,m;//path[N][N]存放上一个结点pair<int, int > t, p原创 2021-08-08 16:32:59 · 77 阅读 · 0 评论 -
线段树_lazytag
1.lazytag是个结点的标记。2.当需要使用线段树进行区间修改的时候,利用线段树存储区间信息的特点,在修改【L,R】区间时,如果区间【a,b】完全包括在【L,R】区间内,就给这个结点打上tag标记同时更新这个结点的值,tag标记的值就是区间需要修改的值。3.当需要用到线段树进行区间查询的时候,如果查询到的结点有tag标记。就将tag标记分给子节点并更新子节点的值,同时清空自己的tag标记。#include<iostream>using namespace std;const..原创 2021-08-01 13:25:35 · 610 阅读 · 0 评论 -
Dijkstra算法证明图解
目录前言:算法步骤参数说明算法描述算法过程图解算法可行性证明一.数学归纳法:假设前提:归纳证明:二.贪吃蛇法(个人理解):前言:Dijkstra算法算是比较经典的一个求单源最短路径的一个算法了,有向图和无向图都可以使用,对于采用邻接表还是邻接矩阵存储图也没有要求。我在一开始学习这个算法的时候,虽然知道算法的具体处理流程,但是对于算法的原理却是一知半解,在做PTA一些算法题的时候遇到了稍微灵活的题目就歇菜了。所以翻看了一写文档,自己归纳整理了一下原理,也有一些自己的想法,如有不当之处,还望批评指正。算原创 2021-02-09 21:18:25 · 2888 阅读 · 1 评论 -
哈希表-开放寻址法-拉链法
开放寻址法和拉链法十分类似,只是处理冲突的方式不一样。拉链法通过在冲突位置开链表解决,开放寻址法通过往后顺次找空位置解决。拉链法:#include<iostream>#include<cstdio>#include<vector>using namespace std;const int N = 1e5+3;vector<int > h[N];int _hash(int x){ return (x%N+N)%N;}voi原创 2021-08-03 22:56:25 · 904 阅读 · 0 评论 -
多项式的除法
这仍然是一道关于A/B的题,只不过A和B都换成了多项式。你需要计算两个多项式相除的商Q和余R,其中R的阶数必须小于B的阶数。输入格式:输入分两行,每行给出一个非零多项式,先给出A,再给出B。每行的格式如下:N e[1] c[1] … e[N] c[N]其中N是该多项式非零项的个数,e[i]是第i个非零项的指数,c[i]是第i个非零项的系数。各项按照指数递减的顺序给出,保证所有指数是各不相同的非负整数,所有系数是非零整数,所有整数在整型范围内。输出格式:分两行先后输出商和余,输出格式与输入格式相同原创 2021-04-01 21:47:00 · 1648 阅读 · 0 评论 -
并查集代码框架
并查集就是用于集合类关系问题,如果仅仅需要判断两个节点是否属于一个连通分量,如果用图作为存储的数据结构,在用dfs遍历,会将问题复杂化,所以用一种新的数据结构----并查集来储存数据,可以极高的提高效率。思路:前提:用fa[i]存储i结点的前驱结点,如果两个结点属于同一个集合,则他们最终的root一定是一样的。1.先创建一个数组fa[max],让fa[i]=i;这一步的作用是让每一个结点都是一个集合。2.读入数据x,y,将包含x的集合和包含y的集合合并为一个集合。3.重复2,直到所有数据录入完成。原创 2021-02-21 19:25:49 · 105 阅读 · 0 评论 -
组合数_卢卡斯定理_费马小定理_高精度组合数
注:当遇到(a/b)mod p(a/b)mod\ p(a/b)mod p的形式时,采用a∗p−1mod pa*p^{-1}mod\ pa∗p−1mod p进行计算。计算p−1p^{-1}p−1时,由于p是质数,采用费马小定理计算p−1p^{-1}p−1。组合数问题1:当求的数较小,但是求得次数较多时,采用打表的方式进行记录查询。#include<iostream>using namespace std;const int N = 1e5+5原创 2021-08-27 22:37:48 · 165 阅读 · 0 评论 -
匈牙利算法
思想:1:有这么一个二分图,一个左边结点只能和一个右边结点配对,求最大配对数量。2.左边第一个寻找配对的结点。2.左边第二个寻找配对的结点。发现出现了冲突,这时冲突的结点,即左边第一个节点考虑更换配对的结点。3.发现左边第一个节点可以更换配对的结点,这时进行更改。4.配对左边第三个结点。发现没有冲突,完成配对。模板题:#include<iostream>#include<cstring>using namespace std;const int N原创 2021-08-11 17:04:55 · 95 阅读 · 0 评论 -
Floyd算法
伪码描述://i到j经过k中转的最短路径for(int k=1;k<=n;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ graph[i][j]=min(graph[i][j],graph[i][k]+graph[j][k]); } }}模板题目:#include<iostream>#include<cstring>using namespace std;const i原创 2021-08-10 19:18:04 · 82 阅读 · 0 评论 -
字符串哈希
如果要高效判断两个字符串是否相等,需要用到字符串哈希。字符串哈希就是将字符串转换根据进制转换的原则,将每个字符串看成一个数字,就可以实现高效查询。如下图,给定一个字符串a:将字符串的左边看做高位,右边看做低位。建立前缀哈希表。这里不考虑冲突的情况,进制取131(经验值)。因为字符串很长时,可能会越界,所以再对他取模264。但是unsigned long long 就是264 所以只需要用unsigned long long 进行存储,溢出相当于取模。当需要取某一个子串时,就采用前缀和的思想,ha原创 2021-08-06 11:09:00 · 530 阅读 · 0 评论 -
欧拉函数及费马定理
公式法求欧拉函数#include<iostream>using namespace std;int main(){ int n; cin>>n; while(n--){ int a; long long res; cin>>a; res = a; for(int i=2;i<=a/i;i++){ //分解质因数原创 2021-08-20 11:37:25 · 251 阅读 · 0 评论 -
C++归并排序求逆序对_模板
归并排序的思想就是对数组分别排序后合并,利用这个思想我们可以再合并是进行逆序对判断。只需要将归并排序做一些小的改动就可以实现求逆序对。#include<iostream>using namespace std;const int N = 1e5 + 5;int a[N],temp[N];int n;int cnt=0;//逆序对数量void merge_sort(int l,int r) { if (l >= r) { return; } int mid =原创 2021-07-30 17:36:37 · 608 阅读 · 0 评论 -
扩展欧几里得解——原理+解不定方程+解同余方程
解方程:ax+by=gcd(a,b)有欧几里得定理得:此方程一定有解int extend_gcd(int a,int b,int &x,int &y) { //扩展欧几里得算法 /* * 这是一个尾递归 * 思路:gcd的扩展,在求gcd(a,b)的同时,解方程ax+by=gcd(a,b) * 因为gcd(a,b)=gcd(b,a%b) * 所以ax+by=bx1+(a-a/b*b)y1 * 化简一下得到:ax+by=ay1+b(x1-a/b*y1);(得到递推式) *原创 2021-05-22 12:32:17 · 454 阅读 · 0 评论 -
acm常用数据结构_树状数组
树状数组(用于求动态前缀和,下标为1处开始使用):树状数组(本质):二进制拆分查询复杂度O(logn)维护复杂度O(logn)一维树状数组(每个节点的管辖范围为2的k次方,k是二进制末尾0的个数):查询思路: sum[1101] -> sum[1100]+sum[1000]+sum[0000] 每次减去一个1后对下标位置相加。修改思路:对修改位的1位加1,直到越界。tree[1010]修改->1100,10000。。。#include<iostream>usin.原创 2021-07-31 19:36:46 · 147 阅读 · 0 评论 -
bellman_ford算法_有负权边的单源最短路问题
当图中存在负权边时,dijkstra算法就不再适用,这是需要用到bellman_ford算法。算法思想是从每次连接所有的边,但是只更新到前一个结点的距离。如果不存在负权环,则在循环n次(结点数量)后一定可以得到答案。伪码描述:for i in n: for j in m: dis[边尾] = min(dis[边尾],back[边头]+边权)题目:代码:#include<iostream>#include<cstring>using namespace std原创 2021-08-10 11:19:13 · 400 阅读 · 0 评论 -
高斯消元解:多元一次方程,多元异或方程
线性代数解多元一次方程,一个小错误卡了半天。。。思路:1.在一列中找到绝对值最大的数2.将该行换到最上面3.将该行第一个元素变成14.消去剩下行的第一个数#include<iostream>#include<cmath>#include<cstdio>using namespace std;const double eps = 1e-6;double arr[105][105];int n;// void debug() {// .原创 2021-08-27 17:22:47 · 316 阅读 · 0 评论 -
素数筛法(筛线性筛+埃氏筛)
筛法埃氏筛线性筛埃氏筛空间复杂度:O(n)时间复杂度:O(nloglogn)思路:如果一个是合数,那他一定有质因数。所以当遇到质数时,将质数的整数倍筛去,最后就可以得到每个数的状态。代码:#include<iostream>using namespace std;const int N = 1e7+5;bool prime[N];//存放数的状态,true为合数,false为素数void getPrime(int n){ for(int i=2;i<=n/i原创 2021-08-15 20:37:12 · 239 阅读 · 0 评论 -
约数(试除法求约数,约数之和,约数个数,欧几里得算法)
求一个数的约数时间复杂度:O(sqrt(n))空间复杂度:O(1)思路:通过a|n可得(n/a)|n。枚举[1,sqrt(n)]的每一个整数,来判断n是否可以被整除。代码:#include<iostream>using namespace std;void solve(int n){ for(int i=1;i<=n/i;i++){ if(n%i==0){ cout<<i<<" "<<n/i<<" "; }原创 2021-08-16 10:51:35 · 599 阅读 · 0 评论 -
SPFA算法_带负权边的单源最短路径
PSFA算法是Bellman_ford算法的一个优化,他的核心思想是:如果当前结点到源点的距离变短了,那么和他有边的结点到源点的距离有可能会变短。伪码描述:q.push(1);st[1] = true;while(!q.empty()){ v = q.front(),q.pop(); st[v] = false; for x in graph[v]{ if(dis[x]>dis[v]+w){ dis[x] = dis[v]+w; if(x不在队列中){ q.pu原创 2021-08-10 16:14:04 · 184 阅读 · 0 评论 -
质数判断(试除法,分解质因数法)
质数基础试除法分解质因数法试除法时间复杂度:O(sqrt(n))思路:当一个数d满足d|n(d整除n的意思)时,(n÷d)|n也一定成立。于是我们只需要枚举2到sqrt(n)的数就可以判断n是否是一个质数。代码:#include<iostream>using namespace std;bool judge(int n){ for(int i=2;i<=n/i;i++){ if(n%i==0) return false; } return true;}i原创 2021-08-15 20:58:18 · 309 阅读 · 0 评论 -
容斥原理_集合相交问题
问题引入:在求如上三个圆围成的面积时,通常是用S(1∪2∪3) = S(1) + S(2) + S(3) - S(1∩2) - S(1∩3) - S(2∩3) + S(1∩2∩3)的方法进行处理。就其原理就是先统计总的,再逐步进行减法。推广S(1U2U...Un)=S(1)+S(2)+...+S(n)S(1U2U...Un)=S(1)+S(2)+...+S(n)S(1U2U...Un)=S(1)+S(2)+...+S(n)−S(1∩2)−S(1∩3)−...−S(1∩n)−S(2∩3)−.原创 2021-08-29 22:11:36 · 1360 阅读 · 0 评论 -
快速幂运算+快速幂求乘法逆元
时间复杂度:O(logp)原理:当计算abmod pa^bmod\ pabmod p时,可以将多次累乘转换为少次累乘。如:a(10)10mod p=a(1010)2mod p=a(1000)2∗a(10)2mod pa^{(10)_{10}}mod\ p = a^{(1010)_2}mod\ p = a^{(1000)_2}*a^{(10)_2}mod \ pa(10)10mod p=a(1010)2mod p=a(1000)原创 2021-08-20 14:10:50 · 288 阅读 · 0 评论 -
中国剩余定理_解一次同余方程组
问题孙子定理是中国古代求解一次同余式组(见同余)的方法。是数论中一个重要定理。又称中国余数定理。一元线性同余方程组问题最早可见于中国南北朝时期(公元5世纪)的数学著作《孙子算经》卷下第二十六题,叫做“物不知数”问题,原文如下:有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?即,一个整数除以三余二,除以五余三,除以七余二,求这个整数。《孙子算经》中首次提到了同余方程组问题,以及以上具体问题的解法,因此在中文数学文献中也会将中国剩余定理称为孙子定理。抽象来说,就是已知m和a求解一次同余方原创 2021-08-27 12:22:44 · 3439 阅读 · 0 评论 -
染色法判定二分图
判断二分图就是判断有没有奇数点环路。如果有,就不是二分图。通过逐步进行1,2染色,判断有没有冲突。没有冲突,就是二分图。#include<iostream>#include<cstring>using namespace std;const int N = 1e5 + 5, M = 2E5 + 5;int h[N], ne[M], e[M], indx;int n, m, color[N];//邻接表void add(int a, int b) { .原创 2021-08-11 16:04:30 · 80 阅读 · 0 评论 -
dijsktra算法模板+板子题
#include<iostream>#include<cstring>using namespace std;const int N = 505,M =1e5+5;int graph[N][N];int dis[N],vis[N];int n,m;void dijkstra(){ memset(dis,0x3f,sizeof dis); dis[1]=0; //每次更新一个点,贪心的思想 for(int i=0;i&l.原创 2021-08-09 11:33:51 · 110 阅读 · 0 评论 -
组合数_卡特兰定理
当求前缀排列问题时,可以尝试将纯数学的逻辑转换为几何的逻辑。例:给定 n 个 0 和 n 个 1,它们将按照某种顺序排成长度为 2n 的序列,求它们能排列成的所有序列中,能够满足任意前缀序列中 0 的个数都不少于 1的个数的序列有多少个。输出的答案对 109+7取模。思路将问题转换为从左下角走到右上角,0往右走,1往上走。就是总的路径数减去经过上红线的路径数。经过上红线的路径按上红线进行对称,一定能走到(n-1,n+1)即计算C2nn−C2nn−1C_{2n}^n-C_{2n}^{n-1}C2原创 2021-08-28 09:29:02 · 205 阅读 · 0 评论 -
acm常见算法考点_线段树
功能:区间查询和单点修改。线段树的本质就是采用空间换取时间的方式,将数组的每一个可能的区间的结果都存储到一个树里面,这样在查询是就很快。因为采用二叉树的形式存储,所以修改区间内一个值的也是log级别的。大概就是这样的一颗树,因为区间二分的平衡性,所以刚刚建立的一颗树肯定是一颗平衡树。所以为了方便,采用静态数组的方式存储树,类丝与堆的方式。代码:#include<iostream>using namespace std;const int N = 1e5 + 5;int a原创 2021-07-30 21:35:42 · 164 阅读 · 0 评论