- 博客(18)
- 收藏
- 关注
原创 动态规划:背包问题(用C/C++实现)
状态计算: 集合的划分 (需要求的是f(N, V))将当前的集合f(i, j)划分为两个子集,分别为含第i个物品的集合f(i-1, j)与不含第i个物品的集合f(i-1, j-vi) + wi,两集合取最大即为结果。状态计算:集合划分,分别是第i个物品选0个f(i – 1, j),第i个物品选1个,第i个物品选2个……状态计算: 集合的划分,分成若干组,分别是第i个物品选0个f(i – 1, j),第i个物品选1个,第i个物品选2个……f(i)只与f(i-1)有关,j与j – vi都只在j的一侧。
2024-04-01 20:21:48
2119
1
原创 二分图问题:染色法、匈牙利算法(用C/C++实现)
一个图是二分图,当且仅当图中不含奇数环(奇数环:环当中的点为基数)。如果它是一个二分图,那么相连的两个点一定属于两个不同集合,可以看作一个染色问题,由于图中不含奇数环,所以染色过程一定不存在矛盾。2. 所连的点已经有与之配对的点,这时要去找到与之配对的点,重新遍历那个点的出边,寻找是否可以让它与没有配对的其他点配对(递归)。这个算法能得出二分图两边成功匹配的最多的边的个数,成功匹配是指,没有两条边共用一个点。dfs(i, 1);二分图:可以将图中所有点划分到两个集合中,边只存在集合之间,集合内无边。
2024-03-30 15:22:01
406
1
原创 最小生成树问题(用C/C++实现)
Step3:选中距离最短的,此处是2号点,与2号点相连且不在集合内的是3号,它们的距离为3,3>2故不需要将3号点进行更新。Step2: 与1号点相连的是2、3、4号点,更新它们到集合内点的最小距离,此时集合内只有1号点故为与1的距离。Step1: 选中1号点,一开始集合内不存在点,故将1号点直接将加入。同时将其他点的距离初始化为正无穷。以此类推,最终得到将这些节点相连的最短距离的边构成的树即为最小生成树。点到集合的距离:该点到集合中点的所有边中长度最小的边。2. 堆优化版的Prim(O(mlogn))。
2024-03-30 15:19:28
600
1
原创 最短路问题(用C/C++实现)
此处备份的原因:在更新这些点的距离时可能会发生串联,即随着一些点的变化,另一些点会随之改变距离,所以要进行备份保证每个点的距离都是上一次的结果。优化了dist[b] = min(dist[b], dist[a] + w)这个式子,当dist[a]更新后变小了,dist[b]才可能会变小。用t更新其他所有点的距离,即看t节点的出边连接的节点到起点的距离能否使用t来更新,dist[x] > dist[t] + w.
2024-03-30 15:15:39
1014
2
原创 树与图的遍历:拓扑排序(用C/C++实现)
每个点的入度是指指向该点的边数,每个点的出度是指从该点指出的边数。以上图为例,1的入度为0,出度为2;3的入度为2,出度为0.一个有向无环图,一定至少存在一个入度为0的点。删除t -> j,因为剩下的所有结点一定在t之后,t是一个完全满足条件的点,故可以删除不再考虑,并且d[j] --,更新j的入度d。1. 邻接矩阵:一个二维数组g[a, b],表示a->b,边的权重即为数组的值,无权重即为bool值,0表示无边,1表示有边。2. 邻接表:单链表,每个节点都有一个单链表,用来存储该点可以走到的点。
2024-03-27 19:34:04
558
1
原创 DFS与BFS(用C/C++实现)
3. BFS会一层一层搜索,将同一层的节点搜索完后再向下一层搜。数据结构是一个队列,空间是O(2h).由于它第一次搜到的点都是最近的点,所以具有最短性(当每条边的权重都为1的时候,那么搜索到的一定是最短路)。2. DFS会先往深处搜索,搜索到最后的一个节点后再进行回溯,回溯到最近的一个有分支的节点后继续往深处搜索。将每个能通过的位置作为节点分析,数字代表第几层(r是指根节点,x是指不能通的路)将x插入队列并更新x的距离d[x] = d[t] + 1;拓展t的所有邻点x;while queue非空。
2024-03-27 19:29:25
788
1
原创 C++STL总结
erase() 如果输入是一个数,删除所有等于这个数的节点O(k + logn);lower_bound(x)/upper_bound(x) 返回大于等于x的迭代器/返回大于x的迭代器。push_back()/pop_back() 在最后插入一个数/把最后一个数删掉。3. string 字符串,重要的函数:substr(), c_str().begin()/end() 第0个数/最后一个数的后面那个数。front()/back() 返回第一个数/返回最后一个数。size() 返回元素个数。
2024-03-26 10:59:49
711
1
原创 Hash表(用C/C++实现)
把目标的小值域存入数组,再进行映射,如h(11)映射到3,则在3这个“槽”下链入11,若有重复的数映射到同一个数,则在原有的基础上链入,形成一条“拉链”.如 A B C D即为(1 2 3 4)p = 1 * p^3 + 2 * p^2 + 3 * p^1 + 4 * p^0.输入x是一个-10^9~10^9的数,经过哈希函数h(x),输出0~10^5的一个数。在1~L-1段中,L-1是第0位,1是L-2位,即p^(L-2)~p^0。在1~R段中,R是第0位,1是R-1位,即p^(R-1)~p^0;
2024-03-26 10:56:18
403
1
原创 用小根堆为例的堆(用C/C++实现)
用堆中的最后一个元素覆盖掉堆顶元素heap[1] = heap[size],size—消去最后一个元素,再用down(1)操作不断下移到合适位置。同上heap[k] = heap[size],size--,进行判断,如果heap[k]的值变大则进行down(k),反之进行up(k)。在整个堆的最后一个位置插入x:heap[ ++size ] = x,再将刚插入的元素不断往上移up(size);堆是一棵完全二叉树(除最后一层以外,上面的每个节点都是非空的,最后一层节点从左到右排列)heap[k] = x;
2024-03-19 19:52:34
617
1
原创 并查集(用C/C++实现)
3. 合并两个集合的方法:把其中一棵树的树根插入另一棵树的树根之下。px是x的集合编号,py是y的集合编号,p[x] = y.每个集合用一棵树来表示。树根的编号就是整个集合的编号。每个节点存储它的父节点,p[x]表示x的父节点。2. 求x的集合编号的方法:while( p[x]!优化:(路径压缩)x一步一步找到了根节点之后,让所有节点全部指向根节点。1. 判断树根方法:if( p[x] == x )三、 变形(维护额外的信息)
2024-03-19 19:46:16
210
1
原创 Trie树(用C/C++实现)
三、 查找:从根结点开始,逐格字母查找,若无法通向某个字母则不存在某个串;若存在某个字符串但结尾字母未标记则也不存在该串,该串仅为某个串的子串。一、 用途:用于高效的存储和查找字符串集合的数据结构。标记每个字符串的结尾字母,用于区分每个独立的单词。
2024-03-19 19:42:10
218
1
原创 KMP算法(用C/C++实现)
一开始ababab都能匹配上,直到c与a不能相配,此时i = 7, j = 6,要将P子串后移重新进行匹配,此时使用next[6] = 4,即在j = 6时前后缀能够匹配的最长子串长度为4,此时只需要看匹配子串之后的第5个位置是否匹配,即a与c是否匹配,然后依次类推。next[8] = 6 子串长度为8时,abababab,最长的匹配的前后缀是ababab和ababab,更长的是abababa和bababab,不匹配,故最大长度为6.更长的前后缀是ab和ba,不匹配,故最大长度为1。
2024-03-15 11:43:08
406
1
原创 数组模拟栈与队列(用C/C++实现)
将这一组数放入栈中,假设我们遍历到了a[y]这个元素之后,如果在a[y]之前存在a[x],a[x] >= a[y],那么我们永远不会选择a[x]了,故a[x]会被a[y]更新掉,即更新掉下降序列。不断更新之后,只剩下单调序列,故为单调栈。我们使用一个队列来维护窗口,在这个队列中,靠左的元素如果更大(小),则我们就不可能会将它输出,即被更新掉,更新完后队列中的最小值即为队头。用的比较多的题型:一列数,找到在它左侧最靠近它且比它小的数,若找到返回该数,找不到返回-1。三、 单调栈(算法时间复杂度O(n))
2024-03-15 11:38:43
370
1
原创 数组模拟链表与邻接表(用C/C++实现)
head->[结点0,值为3] ->[结点1,值为5] ->[结点2,值为7] ->[结点3,值为9] ->[空结点-1]首先让新结点的左箭头指向k结点,右箭头指向k之后的结点;接着让k结点的右箭头指向新结点,k之后的结点的左箭头指向新结点。每个结点拥有两个属性,分别是结点值和下一个结点地址(这里就是下一个结点的结点号),用数组表示即为e[N]与ne[N].让k结点前面的结点的右箭头指向k之后的结点,k之后的结点的左箭头指向k之前的结点。让k结点指向新结点,新结点指向原来k指向的结点。
2024-03-15 11:33:46
447
1
原创 前缀与差分(用C/C++实现)
若要在a数组的区间[l, r]中使每一个元素加c,则只需使得b(l)+c,且使b(r+1)-c。前缀和:有一数组为a(1), a(2), ……, a(n),则前缀和S(i) = a(1) + a(2) +*假定原本的数组全为0,之后做了n次插入操作,如元素一为[1, 1] + a(1),以此类推。构造新数组b(1), b(2),, b(n),使得a(i) = b(1) +原数组为a(1), a(2),二维前缀和:求子矩阵的和(两方向的前缀)构造方法: b = a(1).二、差分(前缀和的逆运算)
2024-01-30 22:42:25
373
1
原创 二分算法(用C/C++实现)
思想与整数二分一致,但浮点数二分无需考虑边界。二分至区间长度足够小(这里事先定义一个很小的数)就可认为已经找到。本质:对于一个区间能够找到某种性质,使得左边部分区间不满足,右边部分区间满足,那么就能找到满足该性质的分界点。
2024-01-26 22:55:19
424
1
原创 两种排序算法——快排与归并(用C/C++实现)
方法一:Step1: 创建两个指针分别指向数组的两端,让它们往数组中间移动.Step2: 左边的指针遇到比x大的数就停下,等待右边指针遇到比x小的数停下后,交换两指针指向的数字。方法二:Step1: 创建两个数组a[ ] b[ ].Step2: 遍历q[ ]中的每个数,小于x的放入数组a[ ],大于x的放入数组b[ ].Step3: 把a, b依次放入q中.3. 递归处理左右两段*时间复杂度 log(n)
2024-01-26 22:52:32
158
1
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人