![](https://img-blog.csdnimg.cn/20210811163403992.jpg?x-oss-process=image/resize,m_fixed,h_224,w_224)
Acwing算法课以及平时学习的算法知识点
文章平均质量分 68
2021年暑假基础算法课学习成果+平时的算法知识点的学习
不依法度
只是向上走,不必听自暴自弃者流的话。有一分热,发一分光。
展开
-
模拟递归思想实现Ackermann函数
#include<iostream>#include<stack>using namespace std;int main(){ //递归唯一出口是m==0,返回n+1 stack<int>a, b; int m, n; cin >> m >> n; a.push(m), b.push(n); while (!a.empty()) { if (m == 0) { while (!a.empty() &&原创 2022-01-19 21:52:46 · 78 阅读 · 0 评论 -
贪心问题-埃及分数
埃及分数推导过程:代码实现:#include<iostream>using namespace std;int gcd(int x, int y) { return !y ? x : gcd(y, x % y);}void EgyptFraction(int A, int B){ cout << A << "/" << B << "="; do { int E = B / A + 1;//C=B/A A = A *原创 2022-01-17 16:40:41 · 175 阅读 · 0 评论 -
回溯法:素数环
#include<iostream>using namespace std;int n = 8;int a[20];//存放素数环bool vis[21];bool isPrime(int x) { for (int i = 2; i <= x / i; i++) { if (x % i == 0) return false; } return true;}void dfs(int beg) { if (beg == n && isPrime(a[原创 2022-01-17 16:40:17 · 56 阅读 · 0 评论 -
递归-汉诺塔
//正月点灯笼永远滴神代码参考–b站up主.正月点灯笼#include<stdio.h>void hanoi(int n, char a, char b, char c){ if (n == 1) printf("%c-->%c\n", a, c); else { hanoi(n - 1, a, c, b); printf("%c-->%c\n", a, c); hanoi(n - 1, b, a, c); }}int main(){ int .原创 2021-01-24 14:44:22 · 86 阅读 · 0 评论 -
分治法:棋盘覆盖+最大子段和+最近点对
看到其他博客写的那么好我觉得简单说一下思路就好(就是懒bushi:我们从4* 4的棋盘看将4* 4棋盘分成4份,每份都是2* 2(4个格子),任意一个格子为特殊点,那么剩下三个点自然而然就是L型骨牌的排放地,那么当前这四个格子就排满了。要想让剩下三份2* 2棋盘能被L型骨牌排满就让每一份2* 2棋盘都有一个特殊点,并且这三个特殊点还得连一块,所有最好的办法就是把除了已经有特殊点的剩下三份2* 2棋盘的相连点设为特殊点(划分依据)比如然后就是代码实现:(tr,tc)是左上角点坐标(行,列),(d原创 2021-10-30 21:45:07 · 116 阅读 · 0 评论 -
Acwing:拓扑序列
拓扑序列题目链接–有向图的拓扑序列只有有向图存在拓扑序列,且有向图不构成环#include<iostream>#include<algorithm>#include<cstring>using namespace std;const int N = 1e5 + 5;int e[N], ne[N], h[N], idx, que[N], n;int Head = 0, Tail = -1, rd[N];//队头出队,队尾入队,数组记录入度void ad原创 2022-01-17 16:18:57 · 246 阅读 · 0 评论 -
并查集2.0
视频地址:哔哩哔哩up主正月点灯笼参考文章:[https://www.cnblogs.com/asdfknjhu/p/12515480.html先简述一下环是怎么找的:#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>#include<string.h>#define VERTICES 6int find_root(int x, int parent[]) // 找到根节点原创 2021-03-06 17:23:46 · 87 阅读 · 0 评论 -
基础贪心集合
前言贪心,顾名思义,就是只看眼前,思考问题的方式可能有些短视,但有些问题就是可以通过贪心求得最优解,问题在于如何贪心并且如何证明贪心能够求得最优解,后面通过几道例题简单点出基础贪心里得一些基础思路。例题题目链接–区间取点这题y总得证明我没法很好理解就不说了,说说我个人得理解,对于证明可能会比较不严谨,只是一个理解。我们将每一个区间按照区间右端点进行排序,然后在每一个区间的右端点取点,如果这个点包含在其他区间内,那包含该点的其他区间就不用取点。其实就是因为我是在右端点取的点,并且每个区间是按右端点原创 2021-08-25 01:31:15 · 173 阅读 · 0 评论 -
基础的动态规划问题
背包01背包01背包问题的模型:有规定的空间和若干物体,每个物体给出体积和权重,每个物体最多取一次,要求在规定空间大小内取得权重和最大或者最小讲一下代码中那个双重循环:for (int i = 1; i <= N; i++) for (int j = 0; j <= V; j++) { f[i][j] = f[i - 1][j]; if (j >= v[i]) f[i][j] = max(f[i-1][j - v[i]] + w[i], f[i][j]); }原创 2021-08-14 22:01:59 · 233 阅读 · 0 评论 -
单调栈+单调队列
例题–单调栈求当前数之前的第一个小于当前数的数解释一下这题的思路:如果暴力查找for (int i = 0; i < n; i++){ int sign = 0; cin >> a[i]; for (int j = i - 1; j >= 0; j--){ if (a[j] < a[i]){ sign = 1; cout << a[j]; break; } if (sign == 0) cout <原创 2021-07-22 15:35:14 · 64 阅读 · 0 评论 -
二分算法模板
模板bool check(int x) {/* ... */} // 检查x是否满足某种性质// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:int bsearch_1(int l, int r)//mid找左边界{ while (l < r) { int mid = l + r >> 1; if (check(mid)) r = mid; // check()判断mid是否满足性质原创 2021-07-16 23:16:22 · 96 阅读 · 0 评论 -
染色法判断二分图+匈牙利算法
二分图二分图是图论中的一种特殊模型,可理解为将一个图中的所有节点分到两个互不相交的集合里面,图中的所有边的两个端点可以分别在两个节点区间找到,是分别!也就是说边不在集合内部。关于如何判断一个图是否为二分图最好的办法就是判断图中是否有奇数环(环边数为奇数)染色法判断二分图题目链接–染色法判断二分图#include<iostream>#include<cstring>#include<algorithm>using namespace std;const原创 2021-08-02 00:22:43 · 79 阅读 · 0 评论 -
高精度模板
加法#include<iostream>#include<algorithm>#include<vector>using namespace std;vector<int> Add(vector<int>A, vector<int>B);int main(){ string a, b; vector<int>A, B; cin >> a >> b; for (int i = a原创 2021-07-18 18:06:38 · 98 阅读 · 0 评论 -
KMP算法2.0+Trie字符串集合
最近在学算法,发现一个更好的kmp算法的模板,在保留之前那篇关于kmp算法1.0的博客的基础下决定整理分析kmp2.0版代码这一段专门提出来作为模板记录:for (int i = 2, j = 0; i <= n; i++) { while (j && pat[j + 1] != pat[i]) j = Next[j]; if (pat[j + 1] == pat[i]) j++; Next[i] = j; } for (int i = 1, j = 0; i原创 2021-07-22 22:54:13 · 307 阅读 · 0 评论 -
关于质数和约数
质数质数和合数是针对所有大于 1 的 “自然数” 来定义的(所有小于等于1的数都不是质数)。质数,又叫素数,指的是一个数除了1和它本身没有其他的约数。试除法求质数试除法的原理是一个数的约数总是成对出现,因此我们判断一个数是否为质数的时候,只需要判断较小的那一个数能否整除该数就行了#include<iostream>using namespace std;bool IsPrime(int x){ if (x < 2) return false; for (int i = 2原创 2021-08-03 22:57:47 · 465 阅读 · 0 评论 -
最近新接触的一些DFS的题目
题目链接–树的重心dfs函数解析int dfs(int x){ vis[x] = true; int sum = 1, cnt = 0; for (int i = h[x]; i != -1; i = ne[i]) if (!vis[e[i]]) { int s = dfs(e[i]);//s求得的是以e[i]为根的一条分支上节点的个数(不包括e[i]) cnt = max(cnt, s);//cnt存的是将连接e[i]的点断开后每条分支上节点个数的最大值 sum += s原创 2021-07-28 14:24:45 · 88 阅读 · 0 评论 -
模拟散列表
这里构造哈希表用的方法和本质是拉链存储,但实现又和开放域存储相似,神奇。idx的作用和之前一篇解释Trie树的构建的方法差不多,可以对比参考一下。分解函数int h[N], e[N], ne[N],idx;1.关于数组存储:这里的h数组就是散列表的基础模型,通过关键词将不同数分配到同一个卡槽去。奇妙的用法在于后面的e和ne数组一级idx,e数组存储的是元素,ne数组存储的是在e数组中与之下标一致的元素的下一个元素的指向,相当于链表中next的作用,idx是指针,帮助构造ne。void Ins原创 2021-07-25 15:06:28 · 196 阅读 · 0 评论 -
容斥原理+简单博弈论(找个时间补充一下sg,希望我记得)
Nim游戏通常的Nim游戏的定义是这样的:有若干堆石子,每堆石子的数量都是有限的,合法的移动是“选择一堆石子并拿走若干颗(不能不拿)”,如果轮到某个人时所有的石子堆都已经被拿空了,则判负(因为他此刻没有任何合法的移动),假设两个人都绝顶聪明。对于Nim游戏的玩家只有两种游戏结局,必败和必胜。一般来说我们只对先手的游戏结局进行分析,这里有一个结论,假设有n堆石子,石子个数分别为a1,a2,a3…,如果满足a1^ a2^ a3^ …^ an=0 ,则先手必败,如果a1^ a2^ a3^… ^an!=0原创 2021-08-02 11:53:20 · 596 阅读 · 0 评论 -
快排+归并(补充了求逆序对)+堆排序+拓扑序列
以左端点为基准void quicksort(int arr[], int beg, int end){ if (beg >= end) return; int key = arr[beg], l = beg - 1, r = end + 1; while (l < r) { do l++; while (arr[l] < key); do r--; while (arr[r] > key); if (l < r) swap(arr[l], arr[r])原创 2021-07-16 10:37:20 · 169 阅读 · 0 评论 -
Prime算法+Kruskal算法
FloydFloyd和Dijkstra有点像,工作原理是每次取距离集合最近的点,将点放入集合中,并更新该点到其他点的距离(dist),这样dist就表示任意节点到集合的最短距离。题目链接 #include<iostream>#include<cstring>using namespace std;const int N = 505;int n, m, G[N][N], dist[N], sum;//G存两点的距离,dist存到生成树的最短距离bool vis[N];原创 2021-08-01 17:01:45 · 819 阅读 · 0 评论 -
关于树和图存储的特别方法
链式前向星关键代码:const int N = 1e+5;int h[2*N], e[2*N], ne[2*N], idx;//h存的是所以与节点x相连的边构成的链的头结点,是每个节点在e/ne数组中对应的idx//e存时的节点元素x,ne存的是对应的e的相邻节点,idx是一个指针bool vis[N];void add(int x, int y)//这一块操作类似链表节点的插入,我在写散列表里面有详细解释,操作相当于头插法{ e[idx] = y; ne[idx] = h[x];原创 2021-07-27 17:42:25 · 92 阅读 · 0 评论 -
前缀和+差分+离散化+区间合并
前缀和前缀和的作用是降低时间复杂度来计算一个区间的数值总和,比如计算S[l]到S[r]区间所有数值的总和,一般的方法就是一个个遍历相加,从l加到r对于单次求和不影响,但是如果多次求和时间复杂度就会差别很大遍历的时间复杂度是O(n);前缀和时间复杂度是O(1);一维前缀说前缀和是一种算法不如说是一种公式:S[i]=a[1]+a[2]+a[3]+…+a[i]区间l到r的和就是a[l]+a[l+1]+…+a[r]=S[r]-S[l-1]为了方便不用进行下标的判断,默认前缀和数据存储从下标1开始,原创 2021-07-20 16:22:43 · 362 阅读 · 0 评论 -
位运算+双指针算法
整数转二进制:#include<iostream>#include<algorithm>using namespace std;int main(){ int n = 10; for (int i = 3; i >= 0; i--) cout << (n >> i & 1);//1010 return 0;}返回整数二进制的最后一位1:#include<iostream>using namespace原创 2021-07-21 20:39:57 · 55 阅读 · 0 评论 -
朴素版Dijkstra算法+堆排序优化版+Bellman-Ford算法+Spfa算法+Floyd算法
朴素版Dijkstra算法题目链接–Dijkstra求最短路径关键代码int Dijkstra(){ dist[1] = 0; for (int i = 1; i <= n; i++){ int t = -1; for (int j = 1; j <= n; j++) if (!vis[j] && (t == -1 || dist[j] < dist[t])) t = j; vis[t] = true; for (int j =原创 2021-07-29 22:04:39 · 267 阅读 · 0 评论 -
基础数论知识点+例题
高斯消元解线性方程组其实思路很简单,就是线性代数的知识,通过将矩阵化简为最简行列式求解(忽然发现线性代数我已经忘差不多了,这次半年啊!半年!对不起lyh和sh,知识全还给他们了)思路很简单,代码实现起来还是有点绕的先说一下思路 :(就是线性代数的思路)找到每一列数据的绝对值的最大值所在行数将该行数据首元素更新为1,其余数据等比例减小,使该行现数据是原数据的倍数将该行数据上移运用该行数据更新未上移的行数据,是的该列(循环是按列执行)元素置0重复以上动作判断解的个数,如果有唯一解,用元素最少原创 2021-08-09 09:42:22 · 1063 阅读 · 0 评论