算法
何智鹏
不想编程的程序员
展开
-
重新理解一遍二分
/ 开区间while (l + 1 < r) // l + 1 = r时结束return l;原创 2023-05-13 18:47:30 · 216 阅读 · 1 评论 -
c++ upper_bound(), lower_bound()
有时候可以代替手写二分原创 2022-09-29 15:22:13 · 371 阅读 · 0 评论 -
字符和数字的转换
字符和数字的转换原创 2022-09-16 14:38:23 · 153 阅读 · 0 评论 -
判断素数c++
判断素数原创 2022-09-10 12:52:18 · 220 阅读 · 0 评论 -
求最大公约数(c++)
最大公约数原创 2022-09-09 13:48:15 · 780 阅读 · 0 评论 -
c++中有关哈希表的STL操作
set基于红黑树实现,可以进行去重和排序操作。O(logn)。一些常用的函数有:s.insert(x);s.erase(x);s.size();s.find(x);s.count(x); //因为有去重性质,count()统计出现的次数要么是0,要么是1,可以替代find()s.empty();unordered_setO(1)。一些常用的函数:s.insert();s.erase();s.find();s.count();s.empty();map<.原创 2022-03-18 17:34:59 · 1531 阅读 · 1 评论 -
与二进制有关的一些操作
n&1把n与1按位与,因为1除了最低位,其他位都为0,所以按位与结果取决于n最后一位,如果n最后一位是1,则结果为1.反之结果为0。&运算通常用于二进制取位操作,例如一个数 & 1的结果就是取二进制的最末位。这可以用来判断一个整数的奇偶,二进制的最末位为0表示该数为偶数,最末位为1表示该数为奇数。...原创 2022-03-17 09:41:18 · 150 阅读 · 0 评论 -
c++实现读入一行字符串
string s;getline(cin, s);典型应用:读入一行,将单词的首字母大写。原创 2022-03-11 16:55:04 · 730 阅读 · 0 评论 -
c++字符串转数字
例如:输入数字1234;string s;cin >> s;for(auto x : s) cout << x - '0' << endl;输出结果:1234原创 2022-02-25 15:42:36 · 473 阅读 · 0 评论 -
2021-05-23
x >> i & 1;x 二进制表示,第 i 位 是1 还是0原创 2021-05-23 11:22:29 · 87 阅读 · 0 评论 -
数论
1、质数定义:在大于1的整数中,如果只包含1和本身这两个约数,就被称为质数(素数)。小于等于1的数既不是质数,也不是合数。质数的判定----试除法\sqrt{n}bool is_prime(int u) { if (u < 2) return false; for (int i = 2; i <= u / i; i ++ ) { if (u % i == 0) return false; } return tr原创 2021-05-13 07:47:03 · 100 阅读 · 0 评论 -
欧几里得算法
int gcd(int a, int b){ return b ? gcd(b, a % b) : a;}原创 2021-05-08 09:37:31 · 85 阅读 · 0 评论 -
最短路算法
一、朴素版Dijkstraint n, m; //n:点的个数 m:边的条数int g[N][N]; //存储每条边 int dist[N]; //存储1号点到每个点的最短距离bool st[N]; //存储每个点的最短路是否已经确定// 求1号点到n号点的最短路,如果不存在则返回-1int dijkstra(){ memset(dist, 0x3f, sizeof dist); dist[1] = 0; for(int i = 0; i &原创 2021-05-05 15:04:37 · 92 阅读 · 0 评论 -
DFS
123的全排列作例子,每个叶节点就是一个答案深搜就是在每个结点不停往深里搜索的搜索方法。深搜很重要的有回溯和剪枝。回溯必须要还原现场打一个比方:回溯就相当于父母把你放在家里出去了,等父母回来如果你把房间弄乱了后果很严重。回溯也是这个道理回溯的代码一般是这样的:for(......){ st[i] = true; //结点被访问 /*......*/; //做一些其他的操作 dfs(u + 1); //递归下一层 st[i] = false; /*.....*/; //还原现场}原创 2021-04-19 21:30:42 · 91 阅读 · 0 评论 -
并查集
干什么:将两个集合合并询问两个元素是否在一个集合当中并查集可以在近乎O(1)的时间复杂度快速支持以上两个操作。基本原理用树的形式维护所有集合,每一个集合的编号是根节点的编号,对于每一个点,都存储一个父节点,当想求某一个点属于哪个集合的时候,可以根据这个点的父节点往上一直找到根节点,当前结点属于的集合的编号就是树根的编号问题1:如何判断树根:if(p[x] == x);问题2:如何求x的集合编号:while(p[x] != x) x = p[x];问题3:如何合并两个集合:px是x的集合编原创 2021-04-18 19:52:24 · 82 阅读 · 0 评论 -
离散化
离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。适用范围:数组中元素数值很大,但个数不是很多。比如将a[]=[1,3,100,2000,500000]映射到[0,1,2,3,4]这个过程就叫离散化。原创 2021-04-11 17:34:37 · 72 阅读 · 0 评论 -
区间合并
什么是区间合并:假如给定 n 个闭区间[ai,bi],其中i=1,2,…,n。任意两个相邻或相交的闭区间可以合并为一个闭区间。例如,[1,2]和[2,3]可以合并为[1,3],[1,3]和[2,4]可以合并为[1,4],但是[1,2] 和 [3,4] 不可以合并。思路按区间左端点排序扫描整个区间,扫描过程中将所有有交集的区间合并,第i个区间与当前维护的区间的关系分三种情况:第i个区间在当前区间的内部,区间合并完以后左右端点st,ed不变第i个区间与当前区间有交集,但不在内部,区间合并原创 2021-04-11 17:22:07 · 2351 阅读 · 0 评论 -
双指针算法
常见问题分类:对于一个序列,用两个指针维护一段区间对于两个序列,维护某种次序,比如归并中合并两个有序序列的操作原创 2021-04-11 15:13:44 · 68 阅读 · 0 评论 -
位运算
求n的第k位数字: n >> k & 1返回n的最后一位1: lowbit(n) = n & -n原创 2021-04-11 15:05:20 · 52 阅读 · 0 评论 -
前缀和
什么是前缀和原数组: a[1], a[2], a[3], a[4], a[5], …, a[n]前缀和 Si为数组的前 i项和前缀和: S[i] = a[1] + a[2] + a[3] + … + a[i]注意: 前缀和的下标一定要从 1开始, 避免进行下标的转换前缀和的作用快速求出元素组中某段区间的和s[i] = s[i - 1] + a[i];模板int main(){ cin >> n >> m; for(int i = 1; i原创 2021-04-09 20:10:38 · 102 阅读 · 0 评论 -
ios::sync_with_stdio(false)
加快cin的读入速度,可以拿来替代scanf原创 2021-04-09 19:55:35 · 377 阅读 · 0 评论 -
二分查找算法模板
算法思路:假设目标在闭区间**[l , r]中, 每次将区间长度缩小一半,当l = r**时,我们就找到了目标 .版本1当我们将区间怕**[l , r]划分成[l, mid]和[mid + 1 , r]时,其更新操作是r = mid** 或者 l = mid + 1; , 计算mid时不需要加1 .int bsearch_1(int l, int r){ while(l < r){ int mid = l + r >> 1; if(check(mid)) r = m原创 2021-04-02 23:08:21 · 87 阅读 · 0 评论 -
优先队列的实现(无指针)
普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。在某些情况下,我们可能需要找出队列中的最大值或者最小值。普通的队列要完成这样的功能,需要每次遍历队列中的所有元素,比较并找出最大值,效率不是很高,这个时候,我们就可以使用一种特殊的队列来完成这种需求,优先队列。优先队列按照其作用不同,可以分为以下两种:最大优先队列:可以获取并删除队列中最大的值最小优先队列:可以获取并删除队列中最小的值一、最大优先队列之前学习过堆,而堆这种结构是可以方便的删除最大的值,所以,接下来我们可以基原创 2021-02-11 09:51:05 · 208 阅读 · 0 评论 -
堆排序无指针实现
实现步骤:1.构造堆;(这个过程要通过不断下沉得到正确的堆)2.得到堆顶元素,此时这个值就是最大值;3.交换堆顶元素和数组中的最后一个元素,此时所有元素中的最大元素已经放到合适的位置;4.对堆进行调整,重新让除了最后一个元素的剩余元素中的最大值放到堆顶;5.重复2~4这个步骤,直到堆中剩一个元素为止。堆构造过程:创建一个新数组,把原数组0-length-1的数据拷贝到新数组的1~length处,再从新数组长度的一半处(leng/2)开始往1索引处扫描(从右往左),然后对扫描到的每一个元素做下沉原创 2021-02-10 20:23:38 · 138 阅读 · 0 评论 -
堆的实现
堆的特性:1.它是完全二叉树,除了树的最后一层结点不需要是满的,其它的每一层从左到右都是满的,如果最后一层结点不是满的,那么要求左满右不满。2.它通常用数组来实现。3.每个结点都大于等于它的两个子结点。这里要注意堆中仅仅规定了每个结点大于等于它的两个子结点,但这两个子结点的顺序并没有做规定。代码package Heap;public class Heap<T extends Comparable<T>> { private T[] items; p原创 2021-02-10 19:24:30 · 168 阅读 · 0 评论 -
按位与运算(&)和按位或运算符(|)
按位与运算(&)定义:参加运算的两个数据,按二进制位进行"与"运算。运算规则:0&0=0 ,0&1=0 ,1&0=0 ,1&1=1总结:两位同时为1,结果才为1,否则结果为0。例如:3&5 即 0000 0011& 0000 0101 = 0000 0001,因此 3&5 的值得1。按位或运算符(|)定义:参加运算的两个对象,按二进制位进行"或"运算。运算规则:0|0=0 ,0|1=1 ,1|0=1 ,1原创 2021-02-07 22:58:45 · 4044 阅读 · 0 评论 -
约瑟夫问题附完整简洁代码
1、问题描述传说有这样一个故事,在罗马人占领乔塔帕特后,39 个犹太人与约瑟夫及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,第一个1开始报数,依次往后,如果有人报数到3,那么这个人就必须自杀,然后再由他的下一个人重新从1开始报数,直到所有人都自杀身亡为止。然而约瑟夫和他的朋友并不想遵从。于是,约瑟夫要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,从而逃过了这场死亡游戏 。2、问题转换41个人坐一圈,第一个人编号为1,第二原创 2021-02-03 21:22:57 · 897 阅读 · 0 评论 -
由数据范围反推算法复杂度以及算法内容
参考:yxc原创 2021-01-17 21:17:08 · 141 阅读 · 0 评论 -
nth_element()函数
这个函数主要用来将数组元素中第k小的整数排出来并在数组中就位,随时调用,可谓十分实用。函数语句:nth_element(数组名,数组名+第k小元素,数组名+元素个数)int main(){ int n,c; cin >> n; cin >> c; for (int i = 0; i<n; i++) { cin >> p[i]; } nth_element(p,p+c,p+n);原创 2021-01-14 12:26:46 · 278 阅读 · 0 评论 -
流水作业调度问题——动态规划
问题描述:n个作业{1,2,…,n}要在由2台机器M1和M2组成的流水线上完成加工。每个作业加工的顺序都是先在M1上加工,然后在M2上加工。M1和M2加工作业i所需的时间分别为ai和bi。求确定这n个作业的最优加工顺序,使得从第一个作业在机器M1上开始加工,到最后一个作业在机器M2上加工完成所需的时间最少。问题分析:一个最优调度应使机器M1没有空闲时间,且机器M2的空闲时间最少。在一般情况下,机器M2上会有机器空闲和作业积压2种情况。方法一、例 设 n = 4(a1,a2,a3,a4) = (3原创 2020-11-18 20:15:51 · 4012 阅读 · 1 评论 -
最小生成树贪心算法
一、引入:1、生成树: 所有顶点均由边连接在一起,但不存在回路的图最小生成树(Minimum Spanning Tree) 即权值和最小的生成树。2、MST性质 (Minimum Spanning Tree)二、Prim算法算法思路:首先就是从图中的一个起点a(这里假设是1)开始,把a加入U集合,然后,寻找从与a有关联的边中,权重最小的那条边并且该边的终点b(这里是3)在顶点集合:(V-U)中,我们也把b(3)加入到集合U中,并且输出边(a,b)的信息,这样我们的集合U就有:{a,b},然后,原创 2020-11-15 11:13:13 · 3150 阅读 · 1 评论 -
单源最短路径——贪心算法
Dijsktra:#include<iostream>using namespace std;const int INF = 0x3f3f3f3f; //表示无穷大const int N = 5; //5个结点//构造图矩阵,c[i][j]表示边(i,j)的权int c[N + 1][N + 1] = { {0, 0, 0, 0, 0, 0}, {0, INF, 10, INF, 30, 100}, {0, INF, INF, 50, INF, INF}, {0, I原创 2020-11-10 21:28:47 · 1001 阅读 · 0 评论 -
电路布线问题
问题描述:在一块电路板的上、下两端分别有n个接线柱。根据电路设计,要求用导线(i,π(i)) 将上端接线柱i与下端接线柱π(i)相连,如下图。其中,π(i),1≤ i ≤n,是{1,2,…,n}的一个排列。导线(I, π(i))称为该电路板上的第i条连线。对于任何1 ≤ i ≤ j ≤n,第i条连线和第j条连线相交的充要条件是π(i)> π(j).π(i)={8,7,4,2,5,1,9,3,10,6}在制作电路板时,要求将这n条连线分布到若干绝缘层上。换句话说,**这个问题是要确定将哪些连线原创 2020-11-08 11:27:08 · 4760 阅读 · 1 评论 -
哈夫曼编码(前缀码)——贪心算法实现
问题描述:哈夫曼编码是广泛地用于数据文件压缩的十分有效的编码方法。其压缩率通常在20%~90%之间。哈夫曼编码算法用字符在文件中出现的频率表来建立一个用0,1串表示各字符的最优表示方式。一个包含100,000个字符的文件,各字符出现频率不同,如下表所示。有多种方式表示文件中的信息,若用0,1码表示字符的方法,即每个字符用唯一的一个0,1串表示。若采用定长编码表示,则需要3位表示一个字符,整个文件编码需要300,000位;若采用变长编码表示,给频率高的字符较短的编码;频率低的字符较长的编码,达到整体编码原创 2020-11-06 19:58:52 · 1865 阅读 · 0 评论 -
n皇后问题(回溯法优化和拉斯维加斯算法)附完整代码,代码简洁
问题描述:在n×n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n后问题等价于在n×n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。算法思路:一、使用回溯法,即先穷举后优化的思想。ps:data[0] = 2表示第1列的第二个先穷举出所有的可能性检查是否符合不在同一行或同一斜线上再优化:不满足的就不执行了if (index > 1) { if (!check_data(data, i原创 2020-11-02 23:27:47 · 5680 阅读 · 0 评论 -
【贪心算法】最优装载
问题提出:有一批集装箱要装上一艘载重量为c的轮船。其中集装箱i的重量为Wi。最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。贪心选择策略:采用重量最轻者先装的贪心选择策略,可产生最优装载问题的最优解。#include<iostream> using namespace std;const int N = 4; //4个货物 void loading(int x[], float w[], float c, int n);int main(){原创 2020-10-26 23:03:43 · 1834 阅读 · 0 评论 -
活动安排问题(贪心算法)
引入: 贪心算法总是做出在当前看来是最好的选择。也就是说贪心算法并不是从整体最优上加以考虑,所做的选择只是在某种意义上的局部最优选择。贪心算法采用自顶向下,以迭代的方法做出相继的贪心选择,每做一次贪心选择就将所求问题简化为一个规模更小的子问题,通过每一步贪心选择,可得到问题的一个最优解,虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪心法不要回溯。能够用贪心算法求解的问题一般具有两个重要特原创 2020-10-22 22:51:54 · 6605 阅读 · 0 评论 -
动态规划实现最优二叉树
问题提出:已知二叉搜索树中每个结点的访问概率,问这颗树整体的搜索时间最短是多少(此时称为最优二叉搜索树)。例:分别以概率:0.1, 0.2, 0.4, 0.3查找四个键:A, B, C, D。第一颗树:0.11 + 0.22 + 0.43 + 0.34 = 2.9第二颗树:0.12 + 0.21 + 0.42 + 0.33 = 2.1哪颗树是最优查找树?穷举法不现实...原创 2020-10-20 13:12:39 · 2670 阅读 · 3 评论 -
最大子段和问题(3种方法)
给定由n个整数(可能为负整数)组成的序列a1,a2, a3… , an, 寻找它的某个连续子段,使得其和最大。例如( -2,11,-4,13,-5,-2 )最大子段是{ 11,-4,13 }其和为20。1、最大字段和问题的简单算法(1)枚举法求解:以a[0]开始: {a[0]}, {a[0],a[1]},{a[0],a[1],a[2]}……{a[0],a[1],……a[n]}共n个以a[1]开始: {a[1]}, {a[1],a[2]},{a[1],a[2],a[3]}……{a[1],a[2],……原创 2020-10-17 16:06:31 · 43822 阅读 · 15 评论 -
0-1背包问题(动态规划解决)
问题提出:给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问:应如何选择装入背包的物品,使得装入背包中物品的总价值最大?算法分析(递归关系):设所给0-1背包问题的子问题的最优值为 m(i,j),即 m(i,j) 是背包容量为 j,可选择物品为 i,i+1,…,n 时0-1背包问题的最优值。由0-1背包问题的最优子结构性质,可以建立计算 m(i,j) 的递归式:注:(3.4.3)式此时背包容量为j,可选择物品为i。此时在对xi作出决策之后,问题处于两种状态之一:(1)背包原创 2020-10-12 20:15:04 · 3477 阅读 · 0 评论