图的应用(Prim算法、Kruskal算法、Dijkstra算法、Floyd算法)

图的应用

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(ElogE)

	初始时为只有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
image-20221027215703376

三种算法的回顾:在这里插入图片描述
参考:王道考研

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值