欢迎来到endl的博客hhh☀☾☽♡♥

浏览器标题切换
把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

算法提高课——图论

图论难点:问题的转化和抽象(可看成特殊的某一类DP)

图论与DP的联系:

 

 

 

 

DP问题(从集合角度分析最优化问题)可以看成从F(0,0)、F(0,1)、F(1,2)......F(0,m)到F(n,m)的最长路。因此DP问题可以转化为拓扑图(一般DP问题的状态间无环)上的最短(长)路。

当DP依赖关系不具有拓扑序时(即存在环时),可以将其转化为最短路,也可以用高斯消元。

//TLE的原因常常是没有memsert

//st数组在不同算法中的用法:

 

单源最短路的建图方式

AcWing 1129. 热浪

//单源最短路模型。朴素堆优化Dijkstraspfa皆可

AcWing 1128. 信使

//数据范围较小,Floyd算法直接处理

//核心:对于每个点来说,它接收到信的时间,等于它到指挥部   的最短距离。

//跑完最短路之后找出所有最短路中的最大值,若为正无穷则说   明该点与起点不连通,输出“-1”即可

//注意预处理时d[i][i]=0。

AcWing 1127. 香甜的黄油

//多源汇最短路问题(可用堆优化DijkstraSpfa

//分析数据范围得知,Floyd算法会超时.所以可以枚举每一个点作为起点时的花费

AcWing 1126. 最小花费

//注意扣除手续费的计算:

  w[i]=1-手续费i (0<w[i]<1)

  100=d[A]*w[1]*w[2]*w[3]*w[4]......

  所以为使d[A]最小,应使w[1]*w[2]*w[3]*w[4]......最大。

//令S=w[1]*w[2]*w[3]*w[4]......

logS=log(w[1]*w[2]*w[3]*w[4]......)

=logw[1]+logw[2]+logw[3]+logw[4]......

因为0<w[i]<1,所以logw[i]<0,logS<0,-logS>0。那么,为使S最大,logS就应最大,-logS就应最小。其中,-logS可以看成是-logw[i]的和。

  所以本题就可以转化成一个最短路问题,故可以用Dijkstraspfa求解。代码可以直接用乘法来实现三角不等式,上述只是为了说明本题运用Dijkstra或spfa的正确性。

AcWing 920. 最优乘车

//sstream读入小技巧(原题未告知一行读入多少数):

 

//注意这道题的特殊性:要求的是换乘次数最少的路线,而非最短路。可以将问题转化,在处于同一路线上的站点之间连一条权值为1的边,然后用经典最短路模型处理。因为所有的边权都是1,所以可以直接写BFS

AcWing 903. 昂贵的聘礼

//tap:建立虚拟源点(标为0号点),表示直接买的价格,此时应注意一共有n+1个点。

//本题需要考虑等级限制:因为等级和等级限制都不超过100,所以可以枚举等级区间,在这个区间内进行Dijkstra,时间复杂度不超过100w。

单源最短路的综合应用

AcWing 1135. 新年好

//最短路+DFS  6*O(m)+5!

  1. 先预处理出从1,a,b,c,d,e出发到其他所有点的单源最短路径
  2. DFS所有摆放顺序,5!,对于每种摆放顺序,可以通过查表的方式算出最短距离。

//当一个数组作为函数的形参被传入时,sizeof函数就无法正常工作,会RE。

AcWing 340. 通信线路

//最短路+二分

//定义在[0,1000001]这个区间中的性质如下:

对于区间中的某一个点,求出从1走到N,最少经过的长度大于x的边的数量是否小于等于k。

//求出从1到N最少经过几条长度大于x的边:

可以将所有的边分类:如果边长大于x,则边权看成1,否则边权是0。可以用双端队列BFS来求从1到N的最短路。

AcWing 342. 道路与航线

//这道题的路径有两种,一种是边权非负的双向边(道路),一种是边权可正可负且无环的单向边(航线)。

//本题spfa会被卡。

  1. 如果边权非负,那么可以Dijkstra算法,时间复杂度是mlogn
  2. 如果是拓扑图,那么不管边权是正是负,均可按拓扑序扫描,时间复杂度是线性的

//航线一定在不同的道路连通块之间,将每一个连通块看成一个点。具体实现方式:

1.先输入所有双向道路,然后DFS出所有连通块,计算两个数组:id[]存储每个点属于哪个连通块;vector<int> block[]存储每个连通块里有哪些点

2.输出所有航线,同时统计出每个联通块的入度

3.按照拓扑序依次处理每个连通块。先将所有入读为0的连通块的编号加入队列中

4.每次从队头取出一个连通块的编号bid

5.将该block[bid]中所有点加入堆中,然后对堆中所有点跑dijkstra算法

6.每次取出堆中距离最小的点ver

7.然后遍历ver的所有邻点j。如果id[ver]==id[j],那么如果j能被更新,则将j插入堆中;如果id[ver]!=id[j],则将id[j]这个连通块的入度减一,如果减成0了,则将其插入拓扑排序的队列中。

//体现单源最短路:

memset(dist,0x3f,sizeof dist);

  dist[S]=0;

AcWing 341. 最优贸易

//最短路算法和DP的结合(本质上DP和最短路算法是有很大交集的,绝大部分DP都可以被看成是拓扑图上的最短路或最长路问题.)。采用类似于DP的思想,把所有从1到n的路径看成一个集合,进行子集的划分。

//假设S1,S2…St都可以走到第K个点.那么:。dmax同理。

//DP问题所说的“无后效性”即转化为一个表示状态的图时,图上是不存在环的,但是这个问题中存在。因此可以用最短路算法处理上面的类DP问题。

//用spfa正确性:

for(迭代n-1次)

for(循环边)用三角不等式更新

  Dijkstra算法中,每个点只出队一次,但是在本题中一个点可以被更新多次,所以Dijkstra算法不适用于这道题。

//从1到k买入的最小值dmin[k]

  从k到n卖出的最大值dmax[k]

  答案即max(dmax[k]-dmin[k])

单源最短路的扩展应用

AcWing 1137. 选择最佳线路

//可以建反向边,求出从终点到每个起点的最短路的最小值

原问题:从每个起点出发,到达终点的所有路径的最小值。

加上虚拟源点之后的问题:从虚拟源点出发,到达终点的所有路线的距离的最小值。将原问题转化成了单源最短路问题。

AcWing 1131. 拯救大兵瑞恩

//应用拆点的思想。最短路中需要拆点,分层的题目.一般都可以用DP的方式先考虑。因为有钥匙等因素的影响,因此f(i,j)并不能只用两维就表示出到点(i,j)的最短距离。仿照DP的思路,我们可以再加一维。

//但是这道题并不能按照DP的方式来写,因为一般能够用DP方式写的题目都需要保证在计算某个状态之前,所有能够更新它的状态都已经被更新了,即其状态与状态之间满足拓扑序。但是这道题某些点之间是可以相互到达的,因此存在环。所以还是要用最短路的方式来写。

//将二维变成一维:f(x,y,state)的前两维可以压缩成一维

//动态规划

一、状态表示:d(x,y,state)

1.集合:所有从起点走到(x,y)这个格子,且当前已经拥有的钥匙是state的所有路线的集合。

2.属性:最短距离

二、状态计算

1.(x,y)这里有一些钥匙,那么可以直接将所有钥匙拿起:

2.向上下左右四个方向走。

(1)没有门和墙

(2)有门,且有匹配的钥匙,之后走到了(a,b):

//状态间存在环形依赖,因此可以将DP转化成图论问题(BFS)

//Taps:

1.用一维数字表示二维位置

2.所有边权都是0或1,因此可以用双端队列,保证时间复杂度是线性的。

AcWing 1134. 最短路计数

//求方案数

  1. 先求出全局最小值是多少
  2. 分别求出每个子集中等于全局最小值的元素个数

//最短路树(拓扑图)上保证不存在边权为0的环,否则答案的方案数则为正无穷。

 

//本题用BFSDijkstra做没有问题,但是不能用spfa

//求方案数时如果有负权边,则先用spfa求一遍最短路,再循环遍历每一条边,若该边满足三角不等式,则加入最短路树中,最后将最短路树建好,再由拓扑序求最短路树上的方案数。

AcWing 383. 观光

//最短路径的条数

次短路径:如果存在比最短路径长度恰好多1的路径,则再把这样的路径条数加上

d[i,0]表示从1到i的最短路径 cnt[i,0]

d[i,1]表示从1到i的次短路径 cnt[i,1]

Floyd算法(兼具DP和图论的性质

1.多源多汇最短路:可在的时间复杂度之内求出任意两点间的最短路

2.传递闭包:将所有可以间接到达的点连上直接到达的边

如果存在i->j这条边,则g[i,j]=1

如果不存在i->j这条边,则

(1) 初始化:d[i,j]=g[i,j]

(2) for(k)

for(i)

for(j)

if(d[i,k]&&d[k,j])

d[i,j]=1;

3.找最小环

4.恰好经过k条边的最短路(倍增思想)

//Floyd和Bellman-Ford、spfa算法都是基于DP

  Dijkstra基于贪心

//动态规划

一、状态表示

d[k,i,j]表示从i到j只经过1~k的话,最短路径是多少

1.集合:所有从i出发,最终走到j,且中间只经过节点编号不超过k的所有路径。

2.属性:路径长度的最小值

二、状态计算

1.所有不含节点k的路径

最小值为d[k-1,i,j]

2.所有包含节点k的路径

最小值为d[k-1,i,k]+d[k-1,k,j]

 

去掉第一维后:

下面来证明循环当中是否可以去掉第一维:

特殊情况:当k=j时,

由于经过预处理,d(k,k)=0,所以d(i,k)=d(i,k)。说明在循环一轮后,d(k,i,k)仍然等于d(k-1,i,k)。同理得d(k,k,j)=d(k-1,k,j)。所以在循环中可以去掉第一维。

AcWing 1125. 牛的旅行

//牧区:节点

  牧场:连通块

//具体思路:

(1) 用floyd算法求出任意两点之间的最短距离

(2) 求maxd[i],表示和i连通的且距离i最远的点的距离

(3) 情况1:答案为所有maxd[i]的最大值

情况2:枚举在哪两个点之间连边,需要满足d[i,j]=INF。答案为

//本题数据较大,INF最好定义为1e20

AcWing 343. 排序

//假定如果A<B,则d(A,B)=1

1.矛盾:d(i,i)=1

2.唯一确定:当i≠j时,d(i,j)、d(j,i)中必有一个是1

3.顺序不唯一

//改良 将变成

 

AcWing 344. 观光之旅

//集合:按照环上编号最大的点分类

如果d(i,j)=d(i,k)+d(k,j),则k为i->j中编号最大的点

AcWing 345. 牛站

//d[k,i,j]表示从i到j,恰好经过k条边的最短路径

 

(本题中可以存在负环)

//满足结合律,那么就可以用倍增(快速幂)的思想处理这道。由d(2,i,j)得到d(4,i,j),再得到d(8,i,j)

  因此时间复杂度可优化为

//因为实际用到的点数远小于总的点数,所以可以把点的编号离散化一遍,降低时间复杂度。

最小生成树(无向边)

 

当前与外界直接相连的权值最小的一条边。这条边一定可以出现在最优解中。

如何证明当前这条边一定可以被选?

假设不选当前边,最终得到了一棵树。然后将这条边加上,那么必然会出现一个环,在这个环上,一定可以找出一条长度不小于当前边的边,那么把当前边替换上去,结果一定不会变差。

AcWing 1140. 最短网络

AcWing 1141. 局域网

//相当于在这个图的每个连通块内,求一棵最小生成树。相当于求原图的“最小生成森林”。

//做Kruskal算法

  1. 将所有边权从小到大排序
  2. 依次枚举每条边a,b,w

如果a和b不连通,那么就将当前边加到最小生成树中去。

//可以用Prim算法时一定可以用Kruskal算法,但用Kruskal算法时不一定可以用Prim算法(例如本题)

AcWing 1142. 繁忙的都市

//普通的最小生成树:所有的边权之和最小

本题中的最小生成树:最大的边权最小

//做法:Kruskal

  1. 将所有边从小到大排序
  2. 从小到大依次枚举每条边,a,b,w

如果a和b已经连通,那么直接pass

如果a和b不连通,那么就将当前边选出来

AcWing 1143. 联络员

//读题->分析模型->算法->代码

1.将所有必选边加到并查集中

2.将所有非必选边从小到大排序

3.从小到大依次枚举每一条非必选边,a,b,w

如果a和b已经连通,直接pass

如果a和b不连通,那么就将当前边选上

//Kruskal算法:可以只实现前一半,也可以在已经有边的前提下继续做后一半

AcWing 1144. 连接格点

//注意!这不是一个最小生成树问题:n个点,m条边,边权可正可负,求将所有点连通的最小边权和是多少?

//O(klogk)->O(k)

//将二维变成一维

//容易冲突的变量名:y1,next,prev,hash

//为了省去排序的时间,先将纵向边(权值为1)加入,再将横向边(权值为2)加入

 

最小生成树的扩展应用

定理

任意一棵最小生成树一定可以包含无向图中权值最小的边

证明:

反证法。假设无向图G=(V,E)存在一棵最小生成树不包含权值最小的边。设e=(x,y,z)是无向图中权值最小的边。把e添加到树中,e会和树上从x到y的路径一起构成一个环,并且环上其他边的权值都比z大。因此,用e代替环上的其他任意一条边,会形成一棵权值和更小的生成树,与假设矛盾。故假设不成立,原命题成立。

推论

给定一张无向图G=(V,E),n=|V|,m=|E|。从E中选出k<n-1条边构成G的加一个生成森林。若再从剩余的m-k条边中选n-1-k条添加到生成森林中,使其成为G的生成树,并且选出的边的权值之和最小,则该生成树一定包含这m-k条边中连接生成森林的两个不连通节点的权值最小的边。

//以上来自《算法竞赛 进阶指南》

AcWing 1146. 新的开始

//建立一个“超级发电站”,将所有矿井与其都连上边

AcWing 1145. 北极通讯网络

//找一个最小的d值,使得将所有权值大于d的边删去之后,整个图形的连通块的个数不超过k。

//Kruskal算法:假设当前已经循环完第i条边。已经求出了由前i条边构成的连通块。

//可以用DFS/BFS+二分,但用并查集的话则无需二分

 

AcWing 346. 走廊泼水节

//对于两个连通块:

  1. 新边<w ×
  2. 新边==w ×
  3. 新边≥w+1 

  这样才能保证图的唯一最小生成树仍是原树。

AcWing 1148. 秘密的牛奶运输

//次小生成树

定义:给一个带权的图,把图的所以生成树按权值从小到大排序,第二小的称为次小生成树。

//非严格次小生成树的边权可以和最小生成树相等,而严格次小生成树则不可以。

定理:对于一张无向图,如果存在最小生成树和(严格)次小生成树,那么对于人格一棵最小生成树,都存在一棵(严格)次小生成树,使得这两棵树只有一条边不同。

方法1:先求最小生成树,再枚举删去最小生成树中的边求解。时间复杂度

方法2:先求最小生成树,然后依次枚举非树边,然后将该边加入树中,同时从树中去掉一条边,使得最终的图仍是一棵树。则一定可以求出次小生成树。

  1. 设T为图G的一棵生成树,对于非树边a和树边b,插入边a,并删除边b的操作记为(+a,-b)
  2. 如果T+a-b之后,仍然是一棵生成树,称(+a,-b)是T的一个可行交换。
  3. 称由T进行一次可行变换所得到的新的生成树集合为T的邻集

定理:次小生成树一定在最小生成树的邻集中。

//以上来自《信息学奥赛一本通·提高篇》

要使得最小,就要使最大。可以枚举n个点,以每一个点为树根,复杂度预处理出每个点到其他所有点的路径上的最大边权。所以时间复杂

 

//也可以用树链剖分进行预处理

1.求最小生成树,标记每条边是树边,还是非树边;同时把最小生成树建立出来。

2.预处理任意两点间的边权最大值dist[a][b]

3.依次枚举所有非树边,求,满足w>dist[a][b]。

//注意:在求严格次小生成树时,不能只预处理两点之间最大的树边,因为当最大树边和当前枚举的非树边长度相同时,就不能替换了,但此时却可以替换长度次大的树边。因此还需同时预处理出长度次大的树边。

负环

01分数规划

求负环的常用方法,基于spfa:(基于抽屉原理)

  1. 统计每个店入队的次数,如果某个点入队n次,则说明存在负环
  2. 统计当前每个点的最短路中所包含的边数,如果某点的最短路所包含的边数大于等于n,则也说明存在环(一般选择这种方法)

将所有点加入队列中,并初始化dist[i]=0。此时可以看成由虚拟源点向所有点都连了一条边,不影响负环的判断。又因为无论dist数组初始化成0还是0x3f3f3f3f,有负环存在都会逐渐减为负无穷,所以初始化成任意值皆可。也没必要memset

当所有点的入队次数超过2n时,我们就认为图中与很大可能是存在负环的。

AcWing 904. 虫洞

AcWing 361. 观光奶牛

//使最大,即01分数规划问题

 ,可用二分

 

  将边权重定义为,判断是否存在正环不一定要把边权取负,可以在spfa中改变判断符号,变成求最长路。

//保留两位小数,二分时>1e-4即可

  同理,若保留三位小数,则>1e-5

AcWing 1165. 单词环

//建图:

  以每个单词的前两个字母和后两个字母为节点,以单词的长度为边,最多建立676个点、10⁵条边

//同样还是01分数规划问题,解法同上题

//优化:在循环时计数,当循环次数cnt>2*n(n为点数)时就可以直接认为存在正环。将队列换成栈也可以。(但在普通题目中无需将队列换成栈,因为栈的效率极低)

差分约束

(1) 求不等式组的可行解

源点需要满足的条件:从源点出发,一定可以走到所有的边。

步骤

  1. 先将每个不等式xi<=xj+c转化成一条从xj走到xi,长度为ck的一条边
  2. 找一个超级源点,使得该源点一定可以遍历到所有边
  3. 从源点求一遍单源最短路

结果

  1. 如果存在负环,则原不等式组一定无解
  2. 如果没有负环,则dist[i]就是原不等式组的一个可行解

//最短路:所有从1->i的路径的最小值

  最长路:所有从1->i的路径的最大值

(2) 如何求最大值或最小值,这里的最值指的是每个变量的最值

结论

如果求的是最小值,则应该求最长路;如果求的是最大值,则应该求最短路。

以求xi的最大值为例:所有从xi出发,构成的不等式链xi<=xj+c1<=xk+c2+c1<=...<=c1+c2+...+ck所计算出的上界,最终xi的最大值等于所有上界的最小值。

同理,若是求最大值,则是求所有下界的最大值。

问题

如何转化xi<=c,其中c是一个常数,这类的不等式

方法

建立一个超级源点,0,然后建立0->xi,长度是c的边即可

AcWing 1169. 糖果

//最小值则求最长路

  相对关系:

 

  绝对关系:

 

//无解情况:是否存在正环

//边数组大小开三倍N(最坏情况下都是A=B,需要建双向边,另外每个点都要和超级源点连一条边)

//优化:如果用队列会TLE几个数据点,所以将队列替换成栈

AcWing 362. 区间

//贪心或差分约束

  首先将所有ai变成ai+1,bi变成bi+1,这样数据范围就变成了[1~50001],为了将0腾出来建立超级源点

//最小值则求最长路(dist数组初始化为-0x3f)

//前缀和思想:Si表示1~i中被选出的数的个数。

//注意:

 

AcWing 1170. 排队布局

//最大值则求最短路

  建立虚拟源点使得,即从虚拟源点向i号点连了一条边。但在实际操作中无需真的建立出虚拟源点,将所有点都入队即可。

 

//无解情况:判断是否存在负环

//由于题目给定的是相对关系,所以可以令X1=0,那么题目所求的Xn-X1就是Xn,只要求出X1到所有点的最短路,如果Xn的值为正无穷,则说明 1 号奶牛和 N 号奶牛间的距离可以任意大,否则1 号奶牛和 N 号奶牛间可能的最大距离即Xn。

//本题需要进行两次spfa,对于第一问,需将所有点都入队,即spfa(n);对于第二问,只需求出X1到其他点的最短路,即spfa(1)。 //注意每次spfa前都要初始化:

 

  cnt数组记录当前路径的边数,即用来判断是否存在负环。

AcWing 393. 雇佣收银员

//最小值则最长路

//num[i]表示i时刻来的人数

  X[i]表示最终从num[i]中挑出来的人数

,也是为了将0腾出来建立超级源点

 

//前缀和思想:令Si为Xi的前i项和,则

 

 

  由于在最后一个式子中有三个变量,所以我们可以直接从小到大在0~1000内枚举,如果找到符合条件的就直接输出,若循环结束仍未找到则说明无解。

//在枚举的过程中,为了体现是个定值,即

 

 

 

最近公共祖先

  1. 向上标记法 O(n)
  2. 倍增法

fa[i,j]表示从i开始,向上走2^j步所能走到的节点。

depth[i]表示深度

//哨兵:如果从i开始跳2^j步会跳过根节点,那么fa[i,j]=0。   depth[o]=0

//步骤:(二进制拼凑法)

(1) 先将两个点跳到同一层

(2) 让两个点同时往上跳,一直跳到它们的最近公共祖先的下一层。

预处理 O(nlogn) //广搜,不会爆栈

查询O(logn)

//j=0,f(i,j)=i的父节点

  j>0,f(i,j)=f(f(i,j-1),j-1)

  1. Tarjan——离线求LCA O(n+m)

//本质上是对向上标记法的优化

在深度优先遍历时,将所有点分成三大类:

1) 已经遍历过,且回溯过的点

2) 正在搜索的分支

3) 还未搜索到的点

AcWing 1172. 祖孙询问

//倍增求lca

AcWing 1171. 距离

//两点之间的最短距离:d(x)+d(y)-2*d(lca(x,y))

//预处理出每个节点到根节点的距离d(i)

//用vector<PII>来存询问,first存查询的另外一个点,second存查询编号

AcWing 356. 次小生成树

//注意要用long long,会爆int

//思路和AcWing 1148. 秘密的牛奶运输相似

//d1[i,j]表示i->j路径上的最大边

  d2[i,j]表示i->j路径上的次大边

 

 

 

 

AcWing 352. 闇の連鎖

//树上差分

  给从x到y的路径上的所有边都加上c:

  

//最后枚举每棵子树:

 

有向图的强连通分量

对于一个有向图,连通分量:对于分量重任意两点u,v,必然可以从u走到v,且从v走到u。

有向图通过缩点(将所有连通分量缩成一个点)变成有向无环图(DAG),即拓扑图,便于求最短(或最长)路、递推。时间复杂度为O(n+m)。

DFS(树枝边、前向边:指向某个子孙、后向边:指向某个祖宗、横叉边)

情况1:存在后向边指向祖先节点

情况2:先走到横叉边,横叉边再走到祖先

Tarjan算法求强连通分量(SCC)

对每个点定义两个时间戳:

dfn[u]表示遍历到u的时间戳

low[u]从u开始走,所能遍历到的最小时间戳是什么。

u是其所在的强连通分量的最高点,等价于dfn[u]==low[u]

//栈中放当前强联通分量中还没有搜完的所有点

  1. 缩点

for(i=1;i<=n;i++)

for(i的所有邻点j)

if(i与j不在同一个SCC中)

加一条新边 id(i)->id(j)

//连通分量编号递减的顺序一定是拓扑序

AcWing 1174. 受欢迎的牛

//先缩点,再在拓扑图里找出出度为零的点。(如果有两个或以上这样的点,本题答案即为0)答案即这个点所代表的强连通分量中的点数。

AcWing 367. 学校网络

//设缩点后有P个起点,Q个终点

//第一问即P

//第二问为max(P,Q)

假设|P|≤|Q|

1) |P|==1 ans=|Q|

2) |P|>1 |Q|≥|P|>1

必能找到两个不同的起点到达不同的终点,设这两个起点分别为p1、p2,终点分别为q1、q2。

//反证:如果找不到这样的两个点,说明所有起点都到达同一个终点q1。但|Q|>|P|,所以必然有q2是来自其中一个起点,得出矛盾。

此时给q1、p2连一条边,则|P’|=|P|-1,|Q’|=|Q|-1。连|P|-1次这样的边,使得|P|=1,那么此时总共连的边数为|Q|-(|P|-1)+|P|-1,即|Q|。

//第二问注意特判:如果只有一个强连通分量,则答案为0

AcWing 1175. 最大半连通子图

//导出子图:从原图中选出一些点,再把所有跟这些点相关的边都选出来(如果两点间有多条边,则应将这些边全部选出)。

  1. Tarjan
  2. 缩点(不能有重边)建图,给边判重
  3. 按拓扑序递推

//第一问:求拓扑图的最长链

//第二问:求最长链的方案数 DP

  设f(i)为表示到i这个点的最长链的长度,g(i)表示到到i这个点的最长链的方案数,s(i)表示i这个强连通分量中的点数。

如果可以从j->i:

1.若f(j)+s(i)>f(i),则f(I)=f(j)+s(i),且g(i)=g(j)

2.若f(j)+s(i)==f(i),则g(i)+=g(j)

//因为连通分量编号递减的顺序一定是拓扑序,所以无需再次建图,只要按照该顺序DP即可。

AcWing 368. 银河

//本题正解:Tarjan算法(稳定,时间复杂度可达线性)

  1. Tarjan
  2. 缩点
  3. 依据拓扑序递推

//本题可以用01分数规划,思路类似AcWing 1169. 糖果 ,将队列换成栈,仍有超时的风险。

 

另外还有两个条件:

1.必须有绝对值

2.超级源点

 

//本题的特殊性:

边权都为正,因此在判断是否存在正环时,只要在某一个强连通分量中有某一条边的权值大于0,就形成了一个正环(因为强联通分量中的任意两点都互相连通)。所以强连通分量中的所有边的权值都要为0,即所有点最终的距离都相等。因此题目变成了在拓扑图上,所有点到起点的最长距离。

//建立了超级源点后,就可以直接Tarjan(o)。

//本题需要用long long

无向图的双连通分量(也叫重连通分量)

边双连通分量e-DCC:极大的不包含桥的连通块

//:删去桥原图不连通

//性质1:不管删掉哪条边,该图仍然连通

  性质2:任意两点之间都存在两条不相交的路径

点双连通分量v-DCC:极大的不包含割点的连通块

//割点:删去割点原图不连通

//每一个割点都至少属于两个连通分量

//两个割点之间的边不一定是桥,桥的两个端点也不一定是割点

  一个点双连通分量不一定是一个边双连通分量,同样地,一个边双连通分量也不一定是一个点双连通分量

边双连通分量:dfn(x)、low(x)

如何找到桥

如何找到所有边的双连通分量

  1. 将所有桥删掉
  2. Stack dfn(x)==low(x)

如何求割点:low(y)≥dfn(i)

(1) 如果x不是根节点,那么x是割点

(2) x是根节点,至少有两个子节点yi满足low(yi)≥dfn(i)

如何求点双连通分量

1) 统计连通块个数 cnt

2) 枚举从哪个块删,再枚举删除哪个点

AcWing 395. 冗余路径

//两条路径没有一条重合的道路

//给定一个无向连通图,问最少加几条边,可以将其变成一个边双连通分量。

//将所有边双连通分量缩点,原图变成了一棵树,再将所有叶子节点连接起来。(cnt为叶子节点的数量)

AcWing 1183. 电力

//求割点 stack

//多组数据记得memset(dfn,0,sizeof dfn)

//孤立点也是双联通分量

 

AcWing 396. 矿场搭建

//给定一个无向图,问最少在几个点上设置出口,可以使得不管哪个点坍塌,其余所有点都可以与某个出口连通。

  1. 出口数量≥2
  2. 分别看每个连通块

1) 无割点 

2) 有割点

  1. 缩点:

1.每个割点单独作为一个点

2.从每个v-DCC向其所包含的每个割点连边

  1. V-DCC度数为1:需在该分量内部(非割点)放一个出口
  2. V-DCC度数>1:无需设置出口

欧拉回路和欧拉路径

哥尼斯堡七桥问题(一笔画)

  1. 对于无向图,所有边都是连通的

(1) 存在欧拉路径的充分必要条件:度数为奇数的点只能有0或2个。

(2) 存在欧拉回路的充分必要条件:度数为奇数的点只能有0个。

  1. 对于有向图,所有边都是连通的

(1) 存在欧拉路径的充分必要条件:要么所有点的出度均等于入度;要么除了两个点以外,其余所有点的出度等于入度,剩余的两个点:一个满足出度比入度多1(起点),另一个满足入度比出度多1(终点)。

(2) 存在欧拉回路的充分必要条件:所有点的出度均等于入度。

实现方式:dfs,在dfs的最后将当前遍历的节点加入队列中

注意:用边判重,时间复杂度可能会很高。可以在走过一条边之后就将这条边删去。在无向图中,由于建了双向边,两条边都要删掉。双向边的编号为(1,2) (3,4) (5,6)......

AcWing 1123. 铲雪车

//由于每个点的入度和出度都相等,从起点可以到任意一条街道,显然本题就是一个欧拉回路。只要将所有街道的长度之和乘2,再除以铲雪车的速度即可。

//注意答案输出的单位转化

//本题乍一看是一道图论题,但实际上通过分析题目不难得出欧拉回路的结论。

AcWing 1184. 欧拉回路

//如何判断无解:

  1. 无向图:

(1) 所有点的度数必须是奇数

(2) 所有边连通

  1. 有向图:

(1) 所有点的入度等于出度

(2) 所有边连通

AcWing 1124. 骑马修栅栏

//保证dfs中for循环里u的所有出边都按照从小到大的顺序,这样输出的答案就会是字典序最小的。

AcWing 1185. 单词游戏

//以字母为点(26个点),以单词为边

判断有向图是否存在欧拉路径

  1. 除了起点和终点外,其余点入度=出度
  2. 所有边都连通(并查集

拓扑排序

拓扑图=有向无环图

将所有入度为0的点入队

对于任意一个点,其前驱点的个数都是有限的

AcWing 1191. 家谱树

//每输入一个孩子,就使孩子的入度++

//拓扑排序模板

AcWing 1192. 奖金

//差分约束求最长路

1) 边权无限制 spfa O(nm)

2) 边权非负 tarjan O(n+m)

3) 边权>0 拓扑排序 O(n+m)

//用拓扑排序来做差分约束问题。每个点都最小,使得总和最小

AcWing 164. 可达性统计

//DP

f(i):所有能从i到达的点的集合

 

集合用长度为n的二进制串表示(例如1011001......),并使用bitset函数

AcWing 456. 车站分级

//暴力建图会超时

//告诉我们很多个a>b,要求最小的等级,即从b->a建立边权为1的边(很裸的查分约束问题)

1.拓扑排序

2.虚拟源点:将n^2的复杂度变成了线性

//若要连接两个集合,可在集合之间建立一个虚拟源点,从左边的集合中的每一个点向虚拟源点建立一条边权为0的边,再从虚拟源点向右边集合中的每一个点建立一条边权为1的边

 ---------------------------------------------------->

 在最后,感谢Gold_stein(xym)同学提供了自己的笔记供我参考 Thanks♪(・ω・)ノ

posted @ 2020-03-22 23:06  endl\n  阅读(1220)  评论(2编辑  收藏  举报