最短路 Dijkstra算法

以下部分转自百度百科


Dijkstra算法是典型最短路算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低。

  Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。

算法描述  (这里描述的是从节点1开始到各点的dijkstra算法,其中Wa->b表示a->b的边的权值,d(i)即为最短路径值)

  1. 置集合S={2,3,...n}, 数组d(1)=0, d(i)=W1->i(1,i之间存在边) or +无穷大(1.i之间不存在边)

  2. 在S中,令d(j)=min{d(i),i属于S},令S=S-{j},若S为空集则算法结束,否则转3

  3. 对全部i属于S,如果存在边j->i,那么置d(i)=min{d(i), d(j)+Wj->i},转2

  Dijkstra算法思想为:设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将 加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。

  算法具体步骤 

  (1)初始时,S只包含源点,即S=v,距离为0。U包含除v外的其他顶点,U中顶点u距离为边上的权(若v与u有边)或 )(若u不是v的出边邻接点)。

  (2)从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。

  (3)以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u(u U)的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。

  (4)重复步骤(2)和(3)直到所有顶点都包含在S中。


下面以hdu2544为例说明具体步骤

题目:http://acm.hdu.edu.cn/showproblem.php?pid=2544

#include<stdio.h>  
#define maxsum 0x3fffffff  
int map[101][101],dist[101],s[101];  
void Dijkstra(int n,int x)  //n,1,递推实现
{      
    int mindis,u,i,j;
    for(i=1;i<=n;i++)
    {          
        dist[i]=map[x][i];//map[x][i] is OK,dist表示i到原点的最小距离!        
        s[i]=0; //printf("%d/n",dist[i]);    
    }      
    s[x]=1;// x=1    
    for(i=2;i<=n;i++) //找出余下的n-1个点,所以循环n-1次!     
    {          
        mindis=maxsum;          
        u=-1; // 找出当前未使用的点j的dist[j]最小值        
        for(j=1;j<=n;j++)        
        if(s[j]==0 && dist[j]<mindis)//------------(2)        
        {              
              u=j;  //保存当前邻接点中最小的            
               mindis=dist[j];          
        }          
        s[u]=1;//u点已存入s集合,最小的!所以放外面 
                        //更新dist        
        for(j=1;j<=n;j++)  //-------------------(3)          
         if(s[j]==0)              
          if( dist[u]+map[u][j]<dist[j] && map[u][j]<maxsum) //从u点发散出去寻找,map[u][j]<maxsum存在权值 ,map[j][u] is OK             
          dist[j]=dist[u]+map[u][j];      
     }  
}  
int main()  
{      
    int n,m,a,b,c,i,j;      
    while(scanf("%d%d",&n,&m)!=EOF)      
    {          
        if(n==0&&m==0) break;          
        for(i=1;i<=n;i++)            
        for(j=1;j<=n;j++)    
        map[i][j]=maxsum;//初始化邻接矩阵        
        for(i=1;i<=m;i++)          
        { 
            scanf("%d%d%d",&a,&b,&c);  
            map[a][b]=map[b][a]=c;//构造邻接矩阵,对称的!无向!        
        }          
        Dijkstra(n,1);         
        printf("%d/n",dist[n]);    
    }      
    return 0;  
}   


复杂度分析

  Dijkstra 算法的时间复杂度为O(n^2)

  空间复杂度取决于存储方式,邻接矩阵为O(n^2)


注意:Prim和Dijkstra算法的区别

在图论中,Prim算法是计算最小生成树的算法,而Dijkstra算法是计算最短路径的算法。二者看起来比较类似,因为假设全部顶点的集合是V,已经被挑选出来的点的集合是U,那么二者都是从集合V-U中不断的挑选权值最低的点加入U,那么二者是否等价呢?也就是说是否Dijkstra也可以计,dist表示i到原点的最小距离!算出最小生成树而Prim也可以计算出从第一个顶点v0到其他点的最短路径呢?答案是否定的,否则就不必有两个算法了。

二者的不同之处在于“权值最低”的定义不同,Prim的“权值最低”是相对于U中的任意一点而言的,也就是把U中的点看成一个整体,每次寻找V-U中跟U的距离最小(也就是跟U中任意一点的距离最小)的一点加入U;而Dijkstra的“权值最低”是相对于v0而言的,也就是每次寻找V-U中跟v0的距离最小的一点加入U

一个可以说明二者不等价的例子是有四个顶点(v0, v1, v2, v3)和四条边且边值定义为(v0, v1)=20, (v0, v2)=10, (v1, v3)=2, (v3, v2)=15的图,用Prim算法得到的最小生成树中v0v1是不直接相连的,也就是在最小生成树中v0v1的距离是v0->v2->v3->v1的距离是27,而用Dijkstra算法得到的v0v1的距离是20,也就是二者直接连线的长度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然可以!以下是使用Dijkstra算法求解最短路径的MATLAB代码示例: ```matlab function [dist, path] = dijkstra(adjMatrix, startNode) numNodes = size(adjMatrix, 1); % 初始化距离数组 dist = inf(1, numNodes); dist(startNode) = 0; % 初始化路径数组 path = cell(1, numNodes); path{startNode} = startNode; % 创建一个标记数组,用于记录节点是否已被访问 visited = false(1, numNodes); % 运行Dijkstra算法 for i = 1:numNodes-1 % 找到当前距离最小的节点 [~, currentNode] = min(dist .* ~visited); visited(currentNode) = true; % 更新与当前节点相邻的节点的距离 neighbors = find(adjMatrix(currentNode, :)); for j = neighbors if ~visited(j) && dist(currentNode) + adjMatrix(currentNode, j) < dist(j) dist(j) = dist(currentNode) + adjMatrix(currentNode, j); path{j} = [path{currentNode}, j]; end end end end ``` 使用示例: ```matlab % 定义一个邻接矩阵表示图的连接关系 adjMatrix = [ 0 3 0 4 0; 3 0 5 0 0; 0 5 0 2 6; 4 0 2 0 1; 0 0 6 1 0 ]; % 调用Dijkstra算法求解最短路径 [startNode, endNode] = deal(1, 5); [dist, path] = dijkstra(adjMatrix, startNode); % 输出结果 disp(['从节点', num2str(startNode), '到节点', num2str(endNode), '的最短距离为:', num2str(dist(endNode))]); disp(['最短路径为:', num2str(path{endNode})]); ``` 这段代码实现了Dijkstra算法的逻辑,并且可以根据输入的邻接矩阵和起始节点,求解出最短路径的距离和路径。希望能对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值