NOIP--图论知识点

1.      概论

图论〔Graph Theory〕是数学的一个分支。它以图为研究对象。图论中的图是由若干给定的点及连接两点的线所构成的图形,这种图形通常用来描述某些事物之间的某种特定关系,用点代表事物,用连接两点的线表示相应两个事物间具有这种关系。

2.      知识点梳理:

Ø  图的概念与表示方式

图实质上也是数据结构的一种形式。在这种形式下,元素与元素之间两两均有关联。

图可用G=(V,E)来表示,其中V是顶点(vertex)的集合,E是边(edge)的集合。E中的每条边是V中的一对顶点(u,v)。如果(u,v)是无序对,则G是无向图,否则G是有向图。

图的表示方法中,通常,结点被用数字编号来表示,我们可以通过它们的编号数字来对他们进行索引。

 

 

对于边的表示,常用的有三种:边目录、邻接矩阵、邻接表。

(1) 边目录:将所有边列成一张表,用结点来表示边。上图用边目录表示如下:

 

 

(2) 邻接矩阵:邻接矩阵是一个n×n的数组(n为结点数)。

在非带权图中,如果E中存在边(i,j),则对应数组的(i,j)元素的值为1,否则为0;在带权图中,如果E中存在边(i,j),则对应数组的(i,j)元素的值为权,否则为0(或INF)。

上图用邻接矩阵表示如下:

 

 

(3) 邻接表:用一个列表列出所有与现结点之间有边存在的结点名称。用一个长度为n的数组来实现(N为结点个数),数组的每一个元素都是一个链表表头。数组的第i元素所连接的链表连接了所有与结点i之间有边的结点名称。

上图用邻接表表示如下:

 

 

以上三种表示方法既可以用于有向图,也可以用于无向图。用于无向图时须进行特殊处理,例如加入两个互为反向的边。

Ø  图的最短路径算法

两个顶点之间的最短路径是指图中连接这两个顶点的路径中代价最小的一条,一条路径的代价是指路径上所有边的权的和。

图的最短路径算法主要有三种:Dijkstra、Bellman-Ford与Floyd算法。前两个用于求解单源最短路径,最后一个用于求解所有节点之间的最短路径。

Dijkstra算法是一种求单源最短路的算法,即从一个点开始到所有其他点的最短路。其基本原理是:每次新扩展一个距离最短的未被扩展的点,更新与其相邻的点的距离。当所有边权都为正时,由于不会存在一个距离更短的没扩展过的点,所以这个点的距离永远不会再被改变,因而保证了算法的正确性。不过根据这个原理,用Dijkstra求最短路的图不能有负权边,因为扩展到负权边的时候会产生更短的距离,有可能就破坏了已经更新的点距离不会改变的性质。Dijkstra算法每一次操作分两步:

(1)找到所有未被更新过的节点中,与源点距离最短的点k。

(2)用该节点更新所有点与源节点的距离:

 

 

在维护所有点与源点的距离时,可用堆来维护。另外,如果要求最短路径,在更新距离时,加入前序节点即可。

Dijkstra算法复杂度为O(N2)。

Bellman-Ford算法也是一种单源最短路的算法,可以解决边权为负的问题。其基本原理为:每次调整枚举所有的边,可以通过这条边更新距离值,则更新,直到没有点的值调整了为止(或者调整n-1次)。

其更新函数与Dijkstra的更新函数一样。不同的是,Bellman-Ford需要枚举边,其复杂度为O(NM),高于Dijkstra,但是Bellman-Ford可以处理负权和负环问题。对于负环,如果调整n-1次以后,还可以继续调整,则表示图中有负环。

SPFA算法是对Bellman-Ford算法的一种加强。由于Bellman-Ford算法中枚举边的操作非常冗余,事实上,只有边对应的顶点有更新,才需要枚举这条边。SPFA就用队列维护顶点,来达到减少枚举的目的。

SPFA执行时,维护一个队列。当某个节点距离值被更新时,加入队列。对于队首元素,枚举以它为起始顶点的边,更新对应节点的距离。对于负环问题,SPFA执行时,需要判断顶点更新次数,当顶点更新次数大于等于n时,则有负环。

Floyd算法与前两种算法不同,它是求解顶点之间两两最短距离。其基本思想是,如果节点i.k的距离加上k,j的距离小于i,j的距离,则更新i,j的距离。该思想与动态规划的思想类似。需要注意的是,在枚举的过程中,需要先枚举k,再枚举ij。Floyed算法时间复杂度为O(N3)。虽然该复杂度与枚举起始节点的Dijkstra算法一致,但是Floyed算法常数复杂度比Dijkstra小很多。

Ø  图的最小生成树算法

在一给定的无向图G=(V,E)中,(u,v)代表连接顶点u与顶点v的边w(u,v)代表此的权重,若存在T为E的子集,使得所有原图的节点联通且w(T)最小,则此T为G的最小生成树。最小生成树其实是最小权重生成树的简称。

求解最小生成树的算法主要有两种:Prim算法和Kruskal算法。

Prim算法是贪心算法,贪心策略为:先随便找一个点作为初始生成树,每次更新时找到目前情况下能连上的权值最小的边的另一端点,加入生成树,直到所有的顶点加入完毕。朴素Prim的时间复杂度是O(n2),因为在寻找离生成树最近的未加入顶点时浪费了很多时间。用堆优化后的Prim算法的时间复杂度为O(mlogn)。

Kruskal算法也是贪心算法,贪心策略为:将边按权值从小到大排序,每次选目前情况下能连上的权值最小的边,若与已生成的树不够成环,加入生成树,直到n-1条边加入完毕。时间复杂度为O(mlogm)。相比于Prim,这个算法更常用。

Ø  二分图与二分图匹配

如果一个图,所有节点可以被分为两类,这两类之间有边相连,但是类内无边相连,那么这个图被称作二分图。

二分图匹配即给定一个二分图G,在G的一个子图M中,M的边集中的任意两条边都不依附于同一个顶点,则称M是一个匹配。图中包含边数最多的匹配称为图的最大匹配。如果所有点都在匹配边上,称这个最大匹配为完美匹配。

求解二分图最大匹配的算法很多,最常用的是匈牙利算法。要说明匈牙利算法,先说明增广路径。

增广路径:若P是图G中一条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径。

由增广路的定义可以推出下述三个结论:

① P的路径长度必定为奇数,第一条边和最后一条边都不属于M。

② P经过取反操作可以得到一个更大的匹配M'。

③ M为G的最大匹配当且仅当不存在相对于M的增广路径。

匈牙利算法是用增广路求最大匹配的算法,其框架为:

(1)置M为空

(2)找出一条增广路径P,通过取反操作获得更大的匹配M'代替M

(3)重复(2)操作直到找不出增广路径为止

匈牙利算法找一条增广路的复杂度为O(m),最多找n条增广路,故时间复杂度为O(mn)。

3.      重难点分析:

v  对于不同的题目,选取合适的算法以及图的表示方法。

v  有向图与无向图的算法有时不一样,需注意。

v  图论相关算法较多而且结构明显,需在平时多练习,并写模板。

 

 

NOIP信息学视频地址

视频地址

链接:https://pan.baidu.com/s/1tHo1DFMaDuMZAemNH60dmw 
提取码:7jgr

posted @ 2020-10-26 14:01  tianli3151  阅读(463)  评论(0编辑  收藏  举报