来源:互联网 发布:mac finder 打开路径 编辑:程序博客网 时间:2024/04/29 01:25

图的表示

邻接表:为每个节点建立一个链表或者数组存放与之连接的节点
邻接矩阵:n*n的矩阵,有边是1,没有边是0

图的搜索

BFS 层次搜索 无回溯 队列 节点判重(记录节点是第几次被访问到的) 路径记录(pre[i]=j,第i个节点的前驱是j,存索引,不存数据本身)
DFS 不断深入 走到头回溯,一般所谓暴力枚举搜索都是DFS,使用栈或者递归,全排列问题,数独问题,八皇后问题…

图的划分

  • 无向图:

    行政区划问题:求给定图G的连通分量的数目解决方案:集合划分,并查集(Union-Find)由于集合中元素是等价的,选择任意一个元 素作为代表,其他元素都指向该元素,即完 成一个集合的表达;称指向元素为子结点, 被指向元素为父结点。(省会)每个集合中具体包含了哪些元素是不关心的,具体选择哪个元素作为代表一般也是不关心的。我们关心的是,对于给定的元素,可以很快的找到这个元素所在的集合(的代表),以及合并两个元素所在的集合,而且这些操作的时间复杂度都是常数级的。[并查集介绍](http://www.cnblogs.com/cyjb/p/UnionFindSets.html)
  • 有向图

    强连通图:对一个有向图,如果每个节点都存在到达其他任何 节点的路径,那么就称它是强连通的。判断有向图是强连通图的方法:任取有向图G的某个节点S,从S开始深度/广度优先搜索,就可以遍历G的所有节点,将G的所有边反向,再次从S开始搜索,如果能够遍历G的所有节点,则G是强连通的。

计算割点

割点:给定某无向连通图G,若删除某结点X已经 与X相邻接的所有边,图G变成非连通图, 则结点X称为图G的割点。

  • 算法

    -使用深度优先搜索,当前刚刚访问结点i,遍历结 点i的相邻结点j;-若j尚未访问,则如果不通过结点i,结点j直接连通的最早结点假定为k:如果k的访问顺序比i早,说明j可以绕过节点i,如果k比j晚,说明要想访问j,必须先经过i,所以,i为割点;-对于根,访问分支多余两个,则根也是割点。

最短路径SPF(Shortest Path First)

  • Dijkatra:

    • 结点集V初始化为源点S一个元素:V={S},到 每个点的最短路径的距离初始化为 dist[u]=graph[S][u];
      • 选择最小的dist[u]则v是当前找到的不在V中且 距离S最近的结点,更新V=V∪{v},调整 dist[u]=min{dist[u],dist[v]+graph[v][u]};
      • 这里写图片描述
  • A*算法:

    A* 算法和Dijkatra都是查找有向图单源点最短路径的问题。 A*算法算法加入了启发式搜索的想法:从S到E的路径中,假定当前位于节点i,则与i相连的节点中,应该选择哪个。
    定义f[j]=g[j]+h[j], g[j]为起始节点S到当前节点j的距离,h[j]从当前节点j到终止节点E的距离。

节点分为三类:活跃节点,待估计节点和计算完成节点。   每次从活跃节点集合中取出f值最小的节点j:       对于j的相邻节点k:           更新g[k]=min(g[k],g[j]+graph[j][k])           更新f[k]=g[k]+h[k]           k归类到活跃节点       j归类到计算完成节点
  • Bellman-ford算法

    -单源点到其他所有节点的最短路径,本质是动态规划
    -若u->v是有向边,d[v]<=d[u]+dis(u,v) 松弛操作
    -对边权无要求,可以发现负环
    -Dijkatra可以看做是优化邻接矩阵值的一个方式,不断填充节点集合。
    -而本方法,三层循环,寻找d[v],我觉得跟Floyd很像

  • SPFA

    -使用队列来存储节点,是对Bellman-ford算法的优化

  • Floyd算法

    -又称为插点法,用于计算图种任意两点的最短路径。
    -dist[i,j]为节点i到j的最短路径的距离,则:
    -dist[i,j]=min{dist[i,k]+dist[k,j],dist[i,j]}
    -i,j,k的取值范围为0-N-1时间复杂度是O(N3),三个for循环,K在最外面
    -如果图中存在负的权值,算法也适用

最小生成树MST

最小生成树要求从一个带权无向连通图中选择n-1 条边并使这个图仍然连通(也即得到了一棵生成树), 同时还要考虑使树的权最小。MST最著名的是Prim 算法和Kruskal算法,它们都是贪心算法。

  • Prim算法:

    -从某个(任意一个)结点出发,选择与该结点邻 接的权值最小的边;随着结点的不断加入,每次都选择 这些结点发出的边中权值最小的:重复n-1次。算法的计算时间是O(n2)

    • 首先以一个结点作为最小生成树的初始结点, 然后以迭代的方式找出与最小生成树中各结点权重最小边,并加入到最小生成树中。
    • 加入之后如果产生回路则跳过这条边,选择下 一个结点。当所有结点都加入到最小生成树 中之后,就找出了连通图中的最小生成树了。
  • Kruskal算法:

    -将边按照权值递增排序,每次选择权值最 小并且不构成环的边,重复n-1次。算法的计算时间是O(eloge)-Kruskal将权值递增的边依次加入到最小生成 树中,若加入时产生回路则跳过该边,继续 尝试加入下一条边。当加入N-1条边时,则 得到了最小生成树。-边集E可以小顶堆的形式保存,一条当前最小成本边可以在O(loge)的时间内找到;-为了快速判断候选边e的加入是否会形成环, 可考虑用并查集的方法:把当前状态的每个 连通子图保存在各自的集合中;候选边是否 可以加入,转化成边的两个顶点是否位于同 一集合中。

    PS:
    Prim算法在得到最小生成树的过程中,始终保 持是一颗树;而Kruskal算法最开始是森林,直 到最后一条边加入,才得到树。

0 0
原创粉丝点击