图的应用
1、最小生成树
最小生成树:一个连通图的生成树,且包含图的所有顶点和尽可能少的边。
对于带权连通无向图G=(V,E)生成树不同,每棵树的权(即数中所有边上的权值之和)也可能不同。设A为图G的所有生出树的集合,若A1为A中边的权值之和最小的那棵生成树,则T称为G的最小生成树(MST)。
有如下性质:
- 最小生成树不是唯一的。
- 最小生成树的权值之和总是唯一的。
- 最小生成树的边数为顶点数减1。
求最小生成树的算法,大多数都利用了最小生成树的一个性质:
若(u,v)时一条具有最小权值的边,其中u∈U,v∈V,则必存在一颗包含边(u,v)的最小生成树。
基于该性质的算法:Prime算法和Kruskal算法
一个通用的最小生成树算法:
Generic_MST(G){
T=NULL;
while T为形成一棵生成树;
do 找到一条最小代价边(u,v)并且加入T后不会产生回路
T=T∪(u,v);
}
2、Prim算法
Prim(普里姆)算法,适合稠密图,顶点少,边多
时间复杂度 O ( ∣ V 2 ∣ ) O(|V^2|) O(∣V2∣)
初始时从图中任取一顶点加入到树T,此时树中只含有一个顶点,之后选择一个与当前T中顶点集合距离最近的顶点,并将该顶点相应的边加入T,每次操作后T中的顶点数和边数都增1。以此类推,直至图中所有的顶点都并入T,得到的就是最小生成树。此时T中必有n-1条边。
简单实现:
void Prime(G,T){
T=⌀;
U={w}; //添加任意顶点w
while((V-U)!=⌀){ //若树中不含全部顶点
找到使u∈U,v∈V且不属于U的最小权值的边(u,v);
T=T∪{(u,v)}; //边归入树
U=U∪{v}; //顶点归入树
}
}
使用两个辅助数组:isJoin[vexnum],记录已经归入生成数的顶点;lowCost[vexnum],记录各节点加入到最小生成树的最小代价,每次加进一个顶点,就更新一次。
2、Kruskal算法
Kruskal(克鲁斯卡尔)算法,适合稀疏图,边少,顶点较多的图
是一种按权值的递增次序选择合适的边来构造最小生成树的方法。
时间复杂度 O ( ∣ E ∣ l o g ∣ E ∣ ) O(|E|log|E|) O(∣E∣log∣E∣)
初始时为只有n个顶点而无边的非连通图T={V,{}},每个顶点自成一个连通分量,然后按照边的权值由小到大的顺序,不断选取当前未被选取过且权值最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入T,否则舍弃此边选择下一条权值最小的边。以此类推,直至T中所有顶点都在一个连通分量上。
简单实现:
void Kruskal(V,T){
T=V; //初始化树T,只含顶点
numS=n; //连通分量数
while(numS>1){ //如果连通分量数大于1
从E中取出权值最小的边(v,u);
if(v和u属于T中不同的连通分量){
T=T∪{(v,u)}; //连通分量数减1
numS--;
}
else 舍弃;
}
}
//可以采用并查集的数据结构来描述T
2、最短路径
求解最短路径的算法通常都依赖于一种性质:即两点之间的最短路径也包含了路径上其他顶点间的最短路径。
带权有向图G的最短路径问题一般可分为两类:一是单源最短路径,即求图中某一顶点到其他各顶点间的最短路径,Dijkstra(迪杰斯特拉)算法;二是求每队顶点间的最短路径,可通过Floyd(弗洛伊德)算法来求解。
1、Dijkstra算法求单源最短路径
Dijkstra,迪杰斯特拉算法。基于贪心策略的
时间复杂度: O ( n 2 ) O(n^2) O(n2)
不适于带负权值的边。
2、Floyd算法求各顶点之间最短路径问题
允许边带负权值,无法解决负权回路的图
这种图没有最短路径。
//堆排序。
基本思想:初始时,对于任意两个顶点vi和vj,若它们之间存在边,则以此边上的权值作为它们之间的最短路径长度;若它们之间不存在有向边,则以∞作为它们之间的最短路径长度。以后逐步尝试在原路径中加入顶点k(k=0,k=1....k=n-1)作为中间顶点。若增加中间顶点后,得到的路径比原来的路径长度减少了,则以此新路径代替源路径。
弗洛伊德算法是一个迭代的算法,每迭代一次,在从vi到vj的最短路径上就多考虑了一个顶点;经过n此迭代后,所得到的A^(n-1)[i][j]就是vi到vj的最短路径长度。
for(k=0;k<n;k++){//可理解为,每两个顶点之间路径的加入k顶点作为中转点,会不会缩短路径
for(i=0;i<n;i++){
for(j=0;j<n;j++){
if(A[i][j]>A[i][k]+A[k][j]){
A[i][j]=A[i][k]+A[k][j];
path[i][j]=k; //记录i到j点的中转站 是 k;
}//if
}//for
}//for
}//for
三种算法的回顾:
参考:王道考研