![](https://img-blog.csdnimg.cn/20201014180756927.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
图论
run around
这个作者很懒,什么都没留下…
展开
-
线段树优化建图
给定n个点,有三种操作:1.连一条从x到y权值为w的边。2.连一条从[l,r]到y权值为w的边。3.连一条y到[l,r]权值为w的边。给定一个起点,求单源最短路。/*线段树优化建图对于点到区间上所有点都加上一条路径这样的操作可以考虑线段树来优化建图将区间考虑成点,那么点到区间的边就变成为点到一些点的边(这些点不会超过log次)线段树的叶子节点就是真实的点线段树每个节点又需要拆为两个点,一个点可以到达它的所有儿子,一个点可以被它的所有儿子到达从这个区间出去一条路径(这个是从其儿子节点跑原创 2021-03-05 20:42:11 · 195 阅读 · 0 评论 -
prufer序列
/*prufer序列prufer序列其实就是将带有标号的n个节点(即每个节点不等价)的树用[1,n]的n-2个数唯一表示即n个点的完全图的生成树与长度为n-2的prufer序列构成一一对应的关系 所以根据prufer序列,我们可以知道,完全图生成树的个数为n^(n-2) */#include <iostream>using namespace std;typedef long long ll;const int maxn = 5e6+5;int f[maxn],p[max原创 2021-03-04 19:48:37 · 166 阅读 · 1 评论 -
克鲁斯卡尔重构树
克鲁斯卡尔重构树就是在用克鲁斯卡尔算法计算最小生成树时,构造出一棵树。当题目需要用到最小生成树时,常常利用重构树将其转化为树上问题。重构过程:在连接两个点时,将其连向一个新点,新点的点权为这条边的边权。并查集上就把这两点的父亲设为这个新点。这样我们就维护了一棵从底向上点权递增的一棵二叉树。这棵树具有很多的性质,以解决不一样的问题。1.对于两个点,他们之间最小路径的最大值就在他们的lca上。2.通过倍增,我们可以求得一个点y在经过的权值不超过z能到达的所有点。倍增到那个点,那个点为根的子树就都是可达原创 2021-01-27 20:35:24 · 1145 阅读 · 0 评论 -
圆方树
圆方树是用于处理无向图上的一类问题,将图的点双连通分量作为一个方点,将这张图变为一棵树,一般观察到题目的要求中点双上具有一些性质时常常可以考虑使用圆方树将图转化为树。在圆方树中,原来的每个点对应一个圆点,每一个点双对应一个方点。所以共有n+c个点,其中n是原图点数,c是原图点双连通分量的个数。而对于每一个点双连通分量,它对应的方点向这个点双连通分量中的每个点连边。每个点双形成一个“菊花图”,多个“菊花图”通过原图中的割点连接在一起(因为点双的分隔点是割点)。圆方树的性质:1.树上只存在“圆圆边”和“圆原创 2021-01-27 11:27:58 · 370 阅读 · 0 评论 -
图的绝对中心与最小直径生成树
图的绝对中心在图中找到一个点,使得它到所有其他点的最短路径的最大值尽可能小。首先绝对中心到最远的两个点的距离一定是相等的。我们直接枚举每条边(u,v),考虑这个绝对中心在距离u为x的位置。这时我们考虑这条边以外的任意一个点w,那么可能的答案为min(dis[u][w]+x,dis[v][w]+g[u][v]-x),我们将其画图,x为横坐标,答案为纵坐标,会发现图像是一条折线。我们多尝试画一些点,会得到一些折线,看图像可以发现最优值只会在折线的最低点取到,而且这些最低点只会出现在交点处。观察会发现dis原创 2021-01-24 12:00:37 · 283 阅读 · 0 评论 -
最长k可重区间集问题
给定n个区间,要求对于数轴上的每个点,不能被超过k个区间覆盖。要求满足条件下选出的区间长度和尽可能大。分析:首先,如果这些区间的端点覆盖都小于k次,那么其他点被覆盖肯定小于k次,所以我们只需要离散化一下,考虑这些端点即可。我们考虑假设k为1,那么如果选择了某一区间的l端点,那么可以直接到这个区间的r,在[l,r]这一区间内的所有点都不能被选了。所以我们对于每个左端点,都连一条流量为1的边(因为只能选一次),费用为长度的边(因为要求最大长度,所以需要费用流)。因为左端点可能不选,所以我们需要将这个端点向原创 2021-01-21 10:27:26 · 263 阅读 · 0 评论 -
带有上下界的网络流
无源汇带上下界的可行流n个点,m条边,每条边有一个流量下界和流量上界,求一种可行方案使得在所有点满足流量平衡条件的前提下,所有边满足流量限制。分析:首先假设每条边的流过的流量为其下界,如果能流量平衡,那么就存在可行解。但是存在着流量不平衡的情况,所以我们需要调整每个边的流量,使得流量平衡。那么每条边可以调整的流量即为上界减去下界,意义就在于若这条边有流量,则最后的可行流会多出这些流量,这样保证最后的可行流不会超出上界。然后对于每个点我们维护其下界情况下的in与out流量。若一个点in[i]>原创 2020-12-17 22:24:05 · 293 阅读 · 0 评论 -
网络流训练总结
1.表达图中点的互斥关系当我们在解题时,需要取某些点,但是取完这些点后,有些点就不能取了,即点与点之间存在互斥关系。但是网络流中连边似乎只有关联的关系,没有这种互斥关系。其实我们可以让互斥的点连边,流量为无穷大。我们尝试用最小割分割他们,最小割后,图不再连通,那么这条边永远不会被走到,即永远不会发生冲突。洛谷2774给定一个n*m的矩阵,每个点都有权值,取了一个点后就不能取周围的点了,求出能取到的最大值。分析后可知,坐标和为奇数的与偶数的互斥,所以构成了一张二分图。对于二分图的互斥,我们对互斥的点原创 2020-12-10 20:20:26 · 248 阅读 · 0 评论 -
斯坦那树
/*斯坦那树:一个无向图,n个点m条边,有k个关键点,求联通这k个点的最小代价由于最后的结果一定是一棵树,所以dp[i][s]表示以i为根,当前连通状态为s的代价,注意每个点都可能为根. dp[i][s]可以由s的子状态转移过来,也可以由别的点j通过i,j这条边与i相连形成以i为根的s即dp[i][s]=min(dp[i][j]+dp[i][s^j]) j为s的子集dp[i][s]=min(dp[i][s],dp[j][s]+val[i][j]) 那么这个式子本质上就是最短路了,对于每次的s,原创 2020-11-16 16:10:23 · 137 阅读 · 0 评论 -
无向图的双连通分量
边双连通分量/*无向图的边双连通分量(e-DCC)及缩点 若一张无向图不存在桥,则称这张图为边双连通图极大边双连通图称为边双连通分量求法:用链式前向星存图方便标记边 找出原图中所有的桥,将桥去掉后形成的各个连通块即为边双连通分量 最后缩点就把双连通分量缩为一个点即可 */#include <iostream>#include <cstring>using namespace std;const int maxn = 5e4 + 5;struct e原创 2020-11-06 17:50:51 · 169 阅读 · 0 评论 -
在图上找环或判环(只找一个环)
在有向图上找环,需要两个数组。visx[i]表示以i为起点已经被遍历过了,并且不存在环。vis[i]表示在当前的搜索树上,i这个点已经被遍历过了,所以当第二次遍历到它时,就可以找到环了。void dfs(int x){ if( vis[x] == 1 ) { flag = x; //flag为循环点,回溯时用来加边 return; } if( visx[x] == 1 )...原创 2020-03-22 18:59:25 · 800 阅读 · 0 评论 -
DAG上找一条最长路径
dp[i]表示从i点出发能找到的最长路径那么对于dp[i]来说,那可以由它的后继节点(拓扑序大的)转移过来:dp[i] = max(dp[i],dp[t]+val(i,t)) t为所有的后继节点。这样操作就免去了拓扑排序的这一步骤,而且很显然我们需要用记忆化搜索的方式自顶向下的更新状态。对于这种边界状态较难枚举的,用自顶向下的方式其实更好实现!!!ll dp[maxn];ll fi...原创 2020-02-10 20:13:14 · 221 阅读 · 0 评论 -
图的第k短路
/*启发式搜索求图的第k短路f[i] = g[i] + h[i]g[i]为到i点当前的花费,h[i]为到终点的最小花费f[i]为评估从起点出发到终点的花费每次取出f[i]最小的点进行bfs到达终点第k次的就是答案 */ #include <iostream>#include <queue>#include <vector>#include ...原创 2019-09-30 23:16:25 · 203 阅读 · 0 评论 -
图的割点与割边
图的割点/*求图的割点tarjan算法:O(m)首先选定一个根节点,从该根节点开始遍历整个图(使用DFS)。对于根节点:计算其子树数量,如果有2棵即以上的子树,就是割点。因为如果去掉这个点。 对于非根节点:维护两个数组dfn[]和low[],dfn[u]表示顶点u第几个被(首次)访问,low[u]表示顶点u及其子树中的点,通过非父子边,能够回溯到的最早的点的dfn值(但不能通过...原创 2019-08-28 20:59:54 · 163 阅读 · 0 评论 -
KM算法
初始化可行顶标的值用匈牙利算法寻找相等子图的完备匹配若未找到增广路则修改可行顶标的值重复上述过程直到找到相等子图的完备匹配为止/*km算法二分图最大权匹配复杂度:O(V*E)*/#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#defi...原创 2019-08-13 10:38:20 · 136 阅读 · 0 评论 -
求图的最小环
/*floyd求图的最小环:O(n^3) 无权图边权为1即可 对于无向图:在flody外层循环至k时我们求得了任意的i,j,允许经过[1...k-1]这些点的最短路径如果此时对于任意的i,j,有g[k][i],dist[i][j],g[j][k]存在且i,j,k两两不同,则说明存在一个k->i->j->k的一个环 对于有向图:只要初始化dist[i][j] = ...原创 2019-08-21 21:49:39 · 598 阅读 · 1 评论 -
网络流算法
/*Dinic算法,理论上界O(n^2*m) */ #include <cstdio>#include <cstring>#include <queue>using namespace std;#define INF 0x3fffffff struct edges{ int to,val,next;}edge[1000005];int...原创 2019-08-12 21:29:34 · 247 阅读 · 0 评论 -
图的深度优先遍历及求联通分量
图有两种遍历方式,每种方式都有它的作用,这里先介绍图的深度优先遍历,及其一个重要的应用,求联通分块原创 2019-05-03 16:40:42 · 801 阅读 · 0 评论 -
图的广度优先遍历及求无权图的最短路径
现在介绍图的广度优先遍历,它一遍用于求图中两个点之间的最短路径bfs求图某一点到所有点之间的最短路径#include <iostream>#include <vector>#include <queue>#define maxn 10using namespace std;int visited[maxn] = {0}, ord[maxn] = ...原创 2019-05-03 17:15:45 · 810 阅读 · 0 评论 -
最小生成树算法 Kruskal算法
Prim算法时间复杂度:Elog(V)Kruskal算法时间复杂度:Elog(E)原创 2019-05-05 16:42:25 · 223 阅读 · 0 评论 -
单源最短路径(Dijkstra算法及优化)
Dijkstra算法用于计算一个有权图中某一点到图中任意一点的最短路径使用前提 :该图没有负权边复杂度 :O(V^2) V为图中的顶点个数,优化后是Vlog(E)算法思想使用一个cost数组,cost[i]表示从起点到编号为i这个点的最短路径使用一个visited数组,用来表示cost[i]是否计算完成从起始点开始,更新与它直接相邻的节点,然后在未计算完成的剩余的点找到花费最少的点...原创 2019-05-05 20:10:05 · 1682 阅读 · 0 评论 -
最小生成树(Prim算法)
Prim算法和Dijkstra算法很像教科书的复杂度是O(V^2),同Dijkstra算法的复杂度。在Dijkstra算法中,可以用优先队列来优化,同样,也可以用优先队列来优化Prim算法,使它的复杂度变成Vlong(E);#include <iostream>#include <vector>#include <algorithm>#include &...原创 2020-05-21 22:27:27 · 599 阅读 · 0 评论 -
带有负权边的单源最短路径(Bellman-Ford算法)
当一张图中存在负权边时,Dijstra算法就无法算出正确的解,这个时候我们要用到Bellman-Ford算法。注意:1 当这张图存在负权环时是无法算出最短路径的,也可以用Bellman-Ford算法判断这张图是否有负权环。2 Bellman-Ford算法一般处理的是有向图,因为如果是无向图,那么如果存在一条负权边,就会构成负权环了...原创 2019-05-08 16:32:17 · 1837 阅读 · 1 评论 -
Bellmn-Ford的优化——spfa的诞生
在Bellman-Ford中我们发现每一次都对所有的点进行松弛操作太浪费时间了,所以就有了spfa的出现算法原理: 只有上一次循环中松弛过的点才有可能参与下一次循环的松弛操作,所以我们利用一个队列即可实现spfa算法算法实现过程: 把起始点入队,然后取出队首元素,松弛相邻的点,如果松弛成功且这个点没有在队列里,那么就把这个点入队。直到队列为空。#include <iostream>...原创 2019-05-08 18:30:30 · 135 阅读 · 0 评论 -
多源最短路径(floyd算法)
我们可以利用dijstra算法计算单源最短路径,bellman-ford和spfa来计算带负边权的单源最短路径。但是当我们需要求图中任意两个点之间的最短路径的时候,floyd算法就派上用场了算法思想 :主要是dp的思想,对于图上任意两个点,它们之间的最短距离,最开始只允许经过1号顶点进行中转,接下来只允许经过1和2号顶点进行中转……允许经过1~n号所有顶点进行中转,求任意两点之间的最短路程。用...原创 2019-05-11 20:22:46 · 2992 阅读 · 0 评论 -
拓扑排序
应用环境: 一个较大的工程往往被划分成许多子工程,我们把这些子工程称作活动。在整个工程中,有些子工程必须在其它有关子工程完成之后才能开始,也就是说,一个子工程的开始是以它的所有前序子工程的结束为先决条件的,但有些子工程没有先决条件,可以安排在任何时间开始。拓扑排序后,在开始每一项活动时,能够保证它的所有前驱活动都已完成,从而使整个工程顺序进行,不会出现冲突的情况。算法流程:(1) 选择一个入度...原创 2019-07-16 15:19:22 · 57 阅读 · 0 评论 -
差分约束系统
对于不等式组:X1 - X2 <= 0X1 - X5 <= -1X2 - X5 <= 1X3 - X1 <= 5X4 - X1 <= 4X4 - X3 <= -1X5 - X3 <= -3X5 - X4 <= -3求出满足情况的x1~x5,这样的问题我们叫做差分约束系统差分约束系统的解法利用到了单源最短路径问题中的三角形不等式。即...原创 2019-07-24 09:34:50 · 92 阅读 · 0 评论 -
求有向图的强连通分量及缩点(tarjan算法)
如果两个顶点可以相互通达,则称两个顶点强连通。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量。那么给定一张图,该如何求出这张图的连通分量呢(同时也可以算出强连通分量)。Tarjan算法是基于DFS的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。#incl...原创 2019-07-24 11:27:35 · 366 阅读 · 0 评论 -
二分图的最大匹配(匈牙利算法)
#include <iostream>#include <cstring>using namespace std;int n,m; //二分图左边节点数和右边节点数 int used[1005],cy[1005]; //used[i]表示为x匹配时是否使用过了 //cy[i]表示与i匹配的节点编号 int g[1005][1005]; ...原创 2019-07-24 15:21:34 · 279 阅读 · 0 评论 -
最大流问题(EK算法)
洛谷3376给出一个网络图,以及其源点和汇点,求出其网络最大流。EK算法:在每条边都加了一条反向的,权值为0的边反向边的作用:留下一个标记,让后面的流有机会让前面的流走另一条路。直接从s到t广搜即可,从s开始不断向外广搜,通过权值大于0的边,直到找到t为止,(在过程中记录下每条边的编号),然后找到该路径上边权最小的边,记为mi,然后最大流加mi,然后把该路径上的每一条边的边权减去mi,每...原创 2019-07-25 18:33:46 · 601 阅读 · 0 评论 -
欧拉回路(hierholzer算法)
方法就是在逐个找回路,并通过回溯,将回路末端到下一个回溯的入口。加入最后确定的路线中,因此叫做逐步插入回路法。需要注意的是,要保证算法的正确性,应该从欧拉路径的端点(即度数为奇数的点)开始遍历。#include <iostream>#include <stack>using namespace std;#define maxn 1005int g[maxn][m...原创 2019-07-22 20:54:03 · 3476 阅读 · 1 评论 -
2-SAT
给定一个布尔方程,判断是否存在一组布尔变量的真值指派是整个方程为真。当布尔方程为合取范式,且每个字句的文字为两个时,称为2-SAT如:(a || b)&& (b || c) && (a || d) …//复杂度为O(n+m)#include <cstdio>#include <vector>#include <queue&g...原创 2019-08-16 15:53:54 · 87 阅读 · 0 评论 -
图的表示(无权图和有权图)
图是一种很重要的数据结构,首先要怎么表示它呢两种方法:邻接矩阵和邻接表两种方式的应用及优点:邻接矩阵:一般用于表示稠密图,若并非稠密图时,复杂度较高,空间浪费严重邻接表 : 一般用于表示稀疏图,节约空间,较于邻接矩阵复杂度低邻接矩阵非常简单就不放代码了。对于无权图,两个点有边置1,没边置0。对于有权图,两个点有边置为权值,没边置为0邻接表表示一张无权图:#include <io...原创 2019-05-01 17:48:17 · 4643 阅读 · 0 评论