1.52k likes | 1.76k Views
浙江林学院 ACM 集训队阶段总结. Write by Zhuangli(zjfc3). 图论 What is that?. 什么是图论 ?. 图论 〔Graph Theory〕 是数学的一个分支。它以图为研究对象。图论中的图是由若 干给定的点及连接两点的线所构成的图形,这种图形通常用来描述某些事物之间的某种特定关系,用点代表事物,用连接两点的线表示相应两个事物间具有这种关系 。 图论本身是应用数学的一部份,因此,历史上图论曾经被好多位数学家各自独立地建立过。关于图论的文字记载最早出现在欧拉 1736 年的论着中,他所考虑的原始问题有很强的实际背景。. 并查集及其拓展.
E N D
浙江林学院ACM集训队阶段总结 Write by Zhuangli(zjfc3)
什么是图论? • 图论〔Graph Theory〕是数学的一个分支。它以图为研究对象。图论中的图是由若 干给定的点及连接两点的线所构成的图形,这种图形通常用来描述某些事物之间的某种特定关系,用点代表事物,用连接两点的线表示相应两个事物间具有这种关系 。 • 图论本身是应用数学的一部份,因此,历史上图论曾经被好多位数学家各自独立地建立过。关于图论的文字记载最早出现在欧拉1736年的论着中,他所考虑的原始问题有很强的实际背景。
并查集及其拓展 • 并查集是一种信息内聚很强的数据结构,它在判定图的连通性以及等价类划分的时空效率上有着不可替代的优势。但并查集的特殊应用也应该有所了解. 以下两类是并查集在实际问题中的特殊拓展,希望大家能够进行快速掌握. • 1.集合计数问题 • 2.二分图识别
集合计数问题 • HDU 1856 More is better 题意: 若A与B认识,B与C认识,则A与C认识,现给你一组人员的关系表,求在这样的不同群组内,拥有最多人数群组的人数。
集合计数问题 • 有什么想法? • 并查后统计并查数组? • 不可行 数据范围10000000 如果逐个统计必定TLE 不能如此暴力…. • 思路如何……想3分钟
集合计数问题 • 联想到并查集的构造原理 • 构造rank数组,在并操作中入手!! • 好,问题解决!!
二分图识别 • HDU 1829 A Bug Of Life • 题意: 假定两只飞虫(Bug)关系表,如A B表示A仰慕B,问是否存在同性的飞虫互相仰慕(也就是同性恋问题).
二分图识别 • 难点:A与B的集合归属不定 • 如何解决?思考!!!
二分图识别 • 非此即彼思想的运用 • 构造数组opp,初始化为本身编号,若A与B有关,首先进行find(A),find(B)的操作,若根相同,则说明A与B属于同一集合,即同性恋,否则执行下面的操作,如果A的opp等于本身,说明A的opp未初始化,使之等于B,否则将A的opp与B进行Unition操作,类似的如果B的opp等于本身,说明B的opp未初始化,使之等于A,否则将B的opp与A进行Unition操作
二分图识别 • 想想为什么? • 二分图的性质决定 • 更深入的二分识别……(如统计最小单元集,如何进行 >_< 课后思考!)
最短路径问题 • 在一个网络图中求解一点到另一点间最短距离及其路径的算法称之为最短路径问题。 • 1、单源正权最短路径 • 2、单源带负权最短路径 • 3、多源最短路径
单源正权最短路径 • 求解单源最短路径的Dijkstra算法,状态转移与贪心准则的完美结合。 • 思想:动态规划 • 策略:贪心( O(Ve) ) • 步骤: 1.构造辅助数组Dis[],Vist[],Dis[i]表示从源点出发到达i点的最短距离,Vist[i]表示i点是否已被访问,算法开始执行时令所有Dis[i]=w(start,i)[不可达为MAX],Vist[start]=true. 2.每次得到Dis[]数组中最小且未被访问过的点i,标记Vist[i]=true,遍历所有与i相关的边,若得到Dis[i]+w(i,j)<Dis[j],则更新Dis[j]=Dis[i]+w(i ,j). 3.如此循环直到所有点均被标记.
单源正权最短路径 • Dijkstra的致命弱点:不能处理带负权的边 • 思考:Why? • 问题出自贪心策略!!若存在负权,则算法将不断更新负权边相关顶点的Dis值,从而导致答案错误!
单源带负权最短路径 • 如何处理Dijkstra的遗留问题? • 摈弃贪心策略 执行松弛技术-----Bellman-ford算法
单源带负权最短路径 • 什么是松弛技术? • 日常生活中的例子~~(1+1猜想) • 松弛技术的本质是首先给予一个物体很高的估价,在每次的迭代中对估价进行修正,在有限次的迭代后使估价与实际值吻合的技术。
单源带负权最短路径 • 思想:若存在N个点的网络,则对于起点到终点最多经过N-1条边 • 策略:有限迭代下的松弛技术
单源带负权最短路径 • 步骤: • 1、开辟辅助数组Dis[],记录源点到点i的最小距离,初始时设所有Dis[]值为MAX,Dis[start]=0. • 2、进行n-1次迭代,对于所有边,若满足Dis[i]<MAX&&Dis[i]+w(i,j)<Dis[j],更新Dis[j]= Dis[i]+w(i,j). • 3、执行完成后,再执行1次迭代,若出现Dis[i]+w(i,j)<Dis[j]的情况,则表明出现了负环,此时不存在最短路径,否则Dis[end]即所求单源最短路径.
单源带负权最短路径 • 算法分析: • 1、迭代v-1次,每次遍历所有边,复杂度O(VE),E为全部边,Dijkstra的复杂度O(Ve),e为部分边…..效率差别很大!! • 2、如何优化?思考!!
单源带负权最短路径 • 优化1:使用bool值Y 标记此次迭代是否进行松弛,若没进行松弛表明已经得到最短路径,因此跳出循环。(常系数优化)--YEN氏优化 • 优化2:使用标记数组以及队列辅助,初始化时推入start点,标记start在队内,每次执行时,将队首推出,标记其不在队内,遍历其邻边,进行松弛操作,将所有不在队内且进行过松弛操作的边相关的点入队直到队列为空(即不再进行松弛操作)--SPFA!!
单源带负权最短路径 • 由优化2得到的正是传说中的SPFA,拥有神一般的效率O(KE),K一般取值3-5。算法如其名Shortest Path Fast Algorithm! • 瓶颈:如何判负环?思考!!! • 当一个点入队次数超过边的次数!需要辅助数组统计各点入队次数,此时的空间与时间效率都极低!!因此此算法在稠密带负环图中的表现不如bellman-ford的YEN氏优化!!请大家慎重选择使用。
多源最短路径 • 当题目要求大量的查询工作时,需要一种算法能在多项式时间内得到所有顶点间的最短距离并保存结果备查。 • Floyed算法应运而生!!
多源最短路径 • 思想:传递关系闭包 • 策略:动态规划O (V*V*V) • 步骤: • 1、对于点k,若存在w(i,k)+w(k,j)<w(i,j),则更新w(i,j)=w(i,k)+w(k,j). • 2、迭代k直到结束
多源最短路径 • 算法分析: • 1、不论正负权,大小通吃 • 2、一次计算,次次查询 • 3、可扩展性强!(关系传递,最长路径)
图的遍历 • 对于网络图G,如何不失一般性的搜索各结点—图的遍历. • DFS(深度优先) • BFS(广度优先) • --不再一一评述
图的表示 • 邻接阵:对于拥有稠密边的图是个很好表示方法 • 隆重推出~_~邻接表:在图的边数有限,点数过多时是一个很好的表示,主要的效率消耗在于结点的动态生成,然而有一种方法……使得动态的表达静态化…效率神一样的提高……
静态邻接表 • ZJFC-1236 环球旅行 • 题意: • ~~中文题自己看!!!
静态邻接表 • 演示Sample的代码 • 优点1、使用辅助数组p[],p[i]为p点邻接的边号,若为-1则表示无边相关,否则可据此访问边数组,通过next值遍历该点邻接的所有边 • 优点2、空间是边相关的O(E),而不是邻接阵的O(V*V),想想吧,V为10W对于邻接阵的恐怖概念… • 优点3、插入操作时,执行三步曲,使表结构成链状,p[]数组得到更新,具有很高的技巧性,对于每次操作只需对p数组的初始化,而不需要对边表进行改动,从动态向静态转变!
静态邻接表 • 邻接表下对Dijkstra的优化 • 上面讲过其时间效率O(Ve)是基于邻接表,而在邻接阵中是O(V*V*V),使用静态邻接表本身就是场轰轰烈烈的优化! • 使用优先队列(二叉堆)!由于使用到贪心策略,我们可以很好想象,优化每次GetMin的操作,即将Dis数组撤消,转换做优先队列,每次取与更新Dis值从原先的O(E+V) 转换为O(logV),算法总效率提高到O(VlogV)
静态邻接表 • 对于环球旅行题目的求解步骤 • 1、使用map(红黑树)进行键值关联 • 2、构造静态邻接表 • 3、二叉堆优化下的Dijkstra求解
最小生成树 • 对于连通下的带权网络图G,存在一个经过所有点而不成回路的连通,使其权和为本网络最小,称为最小生成树。 • 应用:最小代价网络。 • 方法1:Prim算法 • 方法2:Kruskal算法
Prim算法 • 对Dijkstra算法的推广,主算法几乎一模一样。 • 思想:贪心 • 步骤1:第一次首先选择最小的边,并标记边的2个端点 • 步骤2:以后的每次操作都是在被标记点为起点,未被标记点为末点中取最小边,执行连接,并标记末点,直到所有的点被标记
Prim算法 • 复杂度为O(VE),想想还有什么更好优化? • 对!贪心策略的优化一般使用优先队列实现,使GetMin操作为O(logE)! • 于是整体复杂度为O(VlogE)效率大大提高
Kruskal算法 • 一种无视顶点的操作 • 进行该操作需要边结构与并查集 • 思想:贪心 优先队列优化! • 步骤: • 1、得到边序列推入优先队列 • 2、每次得到一条边,使用并查集判断是否连通,若连通则执行并操作。 • 3、迭代直到执行|V|-1次操作
Kruskal算法 • 算法分析 • 1、点无关的操作,只需要边结构,适合多点图,防止邻接阵暴内存。 • 2、实现方便,代码清晰。 • 3、O(VlogE)复杂度,稀疏图的良方!
差分约束初步 • 什么是差分约束? • 对于一组未知解[x1 x2 x3…xn-1 xn]任意两个不同解xi,xj存在xi-xj>=(或<=)C(常数),以此为模型构成的约束系统,称之为差分约束系统。
差分约束初步 • 首先我们回顾下松弛技术,在Bellman-Ford算法中,有一个十分关键的三角不等式Dis[i]+w(i,j)<Dis[j]使得迭代结束后所有的Dis[j]<= Dis[i]+w(i,j)!! • 再结合差分约束系统的概念,任意未知数间存在xi-xj>=(或<=)C,我们取<=情况研究,则要求xi-xj<=C,即xi<=xj+C!! 看出什么了么? • 对!这就是以j为始点,i为末点,C为权,构造出带约束边的图,并以此求得最短路径的算法啊!数与图得到了完美的结合!!
最大流问题 • 在带源点与汇点的带权连通网络G中,求得自源点出发,受各边容量限制最后到达汇点的流量的问题,称之为最大流问题。 • 最大流网络满足3大性质: • 流守恒性 网络内流不增加不减少 • 容量限制 流量受边负载限制 • 反对称性 任意结点 流进多少 流出多少 • 解决方案:FF方法
Ford-Fulkerson方法 • 这是种方法而非算法,在此种方法指导下的算法最坏上界完全相同,但最好下界却各有千秋。 • 增广路径:在残留网络中,从源点出发,可以通过该路径使得所经边残余流量减少,而通向汇点的流量增大。 • 最小割-最大流定理:网络流中,存在的最大流受限制于该网络的最小割。 • E-K算法,此算法是最常用的最大流算法,以BFS为基础,每次选择残余网络中的结点数最少的可增广路径进行增广,直到无法进行下去,此算法的最大特点是最后一次保存的路径是该网络流的最小截集。
二分匹配 • 对于图G,可以将顶点重构为两个集合,每个集合内的点不自交,则该图称之为二部图,对其求解最大匹配的过程称之为二分匹配。在普通二分匹配中,其最小路径覆盖为点数-最大匹配数。 • 不带权二分匹配(匈牙利算法) • 带权二分匹配(KM算法)
匈牙利算法 • 由匈牙利数学家提出的解决二分图匹配的算法。 • 本质是找增广路径。这里的增广路径定义为交错轨,即一端为已匹配点,另一端为未匹配点,如果通过任意顶点的遍历,能够找到这样的路径,则对其取反,必会使匹配数+1,如此迭代直到无法找到这样的路径为止。 • 对最大匹配的题目一般以最小路径覆盖的形式出现。
KM算法 • KM算法是通过给每个顶点一个标号(叫做顶标)来把求最大权匹配的问题转化为求完备匹配的问题的。设顶点Xi的顶标为A[i],顶点Yi的顶标为B [i],顶点Xi与Yj之间的边权为w[i,j]。在算法执行过程中的任一时刻,对于任一条边(i,j),A[i]+B[j]>=w[i,j]始终 成立。KM算法的正确性基于以下定理: 若由二分图中所有满足A[i]+B[j]=w[i,j]的边(i,j)构成的子图(称做相等子图)有完备匹配,那么这个完备匹配就是二分图的最大权匹配。 这个定理是显然的。因为对于二分图的任意一个匹配,如果它包含于相等子图,那么它的边权和等于所有顶点的顶标和;如果它有的边不包含于相等子图,那么它的边权和小于所有顶点的顶标和。所以相等子图的完备匹配一定是二分图的最大权匹配。 • 算法的本质是对匈牙利算法的改进,但实际上却比匈牙利算法早发表几年,其核心仍然是寻找增广路径的过程。
KM算法 • 步骤 • 初始时为了使A[i]+B[j]>=w[i,j]恒成立,令A[i]为所有与顶点Xi关联的边的最大权,B[j]=0。如果当前的相等子图没有完备匹配,就按下面的方法修改顶标以使扩大相等子图,直到相等子图具有完备匹配为止。 • 我们求当前相等子图的完备匹配失败了,是因为对于某个X顶点,我们找不到一条从它出发的交错路。这时我们获得了一棵交错树,它的叶子结点全部是X顶点。现在我们把交错树中X顶点的顶标全都减小某个值d,Y顶点的顶标全都增加同一个值d,那么我们会发现: • 两端都在交错树中的边(i,j),A[i]+B[j]的值没有变化。也就是说,它原来属于相等子图,现在仍属于相等子图。 • 两端都不在交错树中的边(i,j),A[i]和B[j]都没有变化。也就是说,它原来属于(或不属于)相等子图,现在仍属于(或不属于)相等子图。 • X端不在交错树中,Y端在交错树中的边(i,j),它的A[i]+B[j]的值有所增大。它原来不属于相等子图,现在仍不属于相等子图。 • X端在交错树中,Y端不在交错树中的边(i,j),它的A[i]+B[j]的值有所减小。也就说,它原来不属于相等子图,现在可能进入了相等子图,因而使相等子图得到了扩大。 • 现在的问题就是求d值了。为了使A[i]+B[j]>=w[i,j]始终成立,且至少有一条边进入相等子图,d应该等于min{A[i]+B[j]-w[i,j]|Xi在交错树中,Yi不在交错树中}。 • 理解原理就行,在一般情况下KM算法的代码不会调整,因此只要会使用模版,一切不在话下,当然图论本身就是充满了建模的思想,只有好的模型才能有真正的效率!
KM算法 • 效率 O(V*V*V) • KM算法的本质,对于N*N的矩阵每行每列只能取一个数,使其和为最大!!
强连通分支 • 什么是强连通分支? • 强连通分支就是任意两点均可达的有向子图。 • 理论:白色路径定理 • 求解:Tarjan算法
强连通分支 • 什么是时间戳? • DFS进行时,访问到节点所花的时间 • 算法理论依据:DFS时,如果所达的下一个点i已经被访问,则从该点j出发,寻找父节点到i,其间所经过的所有点必为以i为代表的强连通分支上的点(并查实现) • 如何判断是否是该次被访问?时间戳!
强连通分支 • 步骤 • 对于每个顶点,设立Num、Low、Used、Alive四个属性,一个Stack保存当前正在被遍历的顶点; • 每访问一个顶点,将它的Num和Low设立为当前时间戳,Used、Alive设为True,并将顶点入栈; • 对于它的每条边,若边的终点未Used,则访问,而后用终点的Low值更新它的Low值,对于每个Used且Alive的终点,用它的Num值更新当前值; • 访问完毕当前顶点后,若Low与Num相等,说明找到了一个强连通分量,它包括栈中所有在当前顶点上方的顶点,将它们出栈并记下Belong值,出栈的顶点的Alive要置为false。 • 扫描各点Belong值,其代表的点的个数便为强连通分支数!
强连通分支 • 应用 • 1、求解单纯问题 HDU 1269 • 2、缩图技术 (适用于多点多边的关系闭包求解)
待研究的问题 • 次小生成树 • 最优比例生成树 • 最小树型图 • 弦图 • 稳定婚姻问题