Dijkstra算法求最短路径问题

                                   Dijkstra算法求最短路径问题

                                                                                                    ——HM

    图论中最常见的问题就应是最短路径问题了,解决这一问题的几个基本算法有三个:Floyed、Dijkstra和SPFA了。现在我来浅谈一下Dijkstra的思想与实现。

     单纯的Dijkstra并不是很快,算一个点到其余各点的时间复杂度是O(n^2)级别,算每个点到其余各点的复杂度就是O(n^3)了,在提高组竞赛中不占优势,但其进行优化后便很强大了,如用堆优化Dijkstra可以将其复杂度降到O((M+N)logM)了(一说O(MlogM)),可谓强大。

       那现在我们先放下偏见,了解一下最简单的Dijkstra算法。

      这个算法是用了动态规划和贪心的思想,即按照从源点到其余每一顶点的最短路径长度的升序,依次求出从源点到各顶点的最短路径及长度。

       看不懂是吧,我用图来解释。

       假设有一个有向图如下:

      

 12345
s10000
dist03INFINF30
pathv1v1,v2  v1,v5

    下面开始进行第一次运算,求出从源点v1到第一个终点的最短路径。首先从s元素为0的对应dist元素中,找出值最小的元素,求得dist[2]的值最小,所以第一个终点为v2,最短路径为path[2]=<v1,v2>,最短距离为dist[2]=3.

    接着把s[2]置为1,表示v2已加入S集合中。然后,以v2为新考虑的中间点,对s元素为0的每个顶点vj(此时3≤j≤5)的目前最短路径长度dist[j]和目前最短路径path[j]进行必要的修改.因dist[2]+GA[2,3]=3+25=28,小于dist[3]=∞,所以将28赋给dist[3],将path[2]并上v3后赋给path[3].

    同理,因dist[2]+GA[2,4]=3+8=11,小于dist[4]= ∞,所以将11赋给dist[4],将path[2]并上v4后赋给path[4],最后再看从v1到v5,以v2作为新考虑的中间点的情况。

    由于v2到v5没有边,故GA[2,5]= ∞,因而dist[2]+GA[2,5]不小于dist[5],因此,dist[5]和path[5]无需修改,应维持原值。

      至此,第一次运算结束,三个一维数组的当前状态为:

 12345
s11000
dist03151123
pathv1v1,v2v1,v2,v3v1,v2,v4v1,v5

   dist数组就是单点到每个点的最短路径。

最后上代码:

#include <iostream>
#define now dist[m]+ga[m][j]
#define SIZE 10005
using namespace std;

void clear();

int n,e,w,str,maxv=0,m;
int dist[SIZE],ga[SIZE][SIZE],s[SIZE];

int main()
{
	cin>>n>>e;
	for (int i=1;i<=e;i++){
	    int x,y;
	    cin>>x>>y>>w;
	    ga[x][y]=w;
	}
	
	cin>>str;
	
	for (int i=1;i<=n-2;i++){
		w=maxv;
		m=str;
		for (int j=1;j<=n;j++)
			if (s[j]==0 && dist[j]<w){
			    m=j;
			    w=dist[j];
			}
		s[m]=1;
		for (int j=1;j<=n;j++)
		    if (s[j]=0 && now<dist[j])
	                dist[j]=now;
	}
	
	for (int i=1;i<=n;i++)
	    cout<<dist[i]<<' ';
	
	return 0;
}

void clear()
{
	for (int i=1;i<=n;i++){
		if (i!=str) s[i]=0; 
		else	    s[i]=1;
		dist[i]=ga[str][i];
	}
}

    谢谢观看。

首先,给定一个加权有向图,假设我们要从顶点V0到其他各顶点之间的最短路径。我们可以使用Dijkstra算法来解决这个问题。下面是Dijkstra算法的步骤: 1. 创建两个集合S和Q。S表示已经找到最短路径的顶点集合,Q表示还未找到最短路径的顶点集合。 2. 初始化距离数组dist,表示从V0到其他各顶点的距离。对于V0, dist[V0]=0;对于其他各顶点,dist[i]=无穷大。 3. 将V0加入集合S,将其他顶点加入集合Q。 4. 对于V0的邻居节点i,更新dist[i],即dist[i]=weight(V0,i),其中weight(V0,i)表示从V0到i的边的权重。 5. 从Q中选择dist值最小的顶点u,将u加入集合S,从Q中删除u。 6. 对于u的每个邻居节点v,如果v不在集合S中,更新dist[v],即dist[v]=min{dist[v],dist[u]+weight(u,v)},其中weight(u,v)表示从u到v的边的权重。 7. 重复步骤5-6直到集合Q为空。 8. 最短路径长度为dist数组中的值,最短路径可以通过记录每个顶点的前驱节点来生成。 下面是一个示例,假设有以下加权有向图: ![Dijkstra图示例](https://cdn.luogu.com.cn/upload/image_hosting/brp8g8uj.png) 我们要从顶点V0到其他各顶点之间的最短路径。 1. 创建集合S和Q。初始状态:S={V0},Q={V1,V2,V3,V4,V5}。 2. 初始化dist数组。dist[V0]=0,其他各顶点dist[i]=无穷大。 3. 对于V0的邻居节点,更新dist数组。dist[V1]=10,dist[V2]=5,dist[V3]=无穷大,dist[V4]=无穷大,dist[V5]=无穷大。 4. 从Q中选择dist值最小的顶点V2,将其加入集合S。更新dist数组。dist[V3]=11,dist[V4]=15,dist[V5]=9。 5. 从Q中选择dist值最小的顶点V5,将其加入集合S。更新dist数组。dist[V4]=14。 6. 从Q中选择dist值最小的顶点V1,将其加入集合S。更新dist数组。dist[V3]=9。 7. 从Q中选择dist值最小的顶点V3,将其加入集合S。更新dist数组。没有需要更新的dist值了。 8. 最短路径长度为dist数组中的值,最短路径可以通过记录每个顶点的前驱节点来生成。例如,V1的前驱节点为V2,V2的前驱节点为V0,V3的前驱节点为V1,V4的前驱节点为V5,V5的前驱节点为V0。 因此,从顶点V0到其他各顶点之间的最短路径以及最短路径长度分别为: | 顶点 | 最短路径 | 最短路径长度 | | --- | --- | --- | | V0 | - | 0 | | V1 | V0 -> V2 -> V1 | 15 | | V2 | V0 -> V2 | 5 | | V3 | V0 -> V2 -> V1 -> V3 | 14 | | V4 | V0 -> V5 -> V4 | 23 | | V5 | V0 -> V5 | 9 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值