dijkstr求最短路 邻接矩阵 邻接表

13 阅读3分钟

dijkstr算法用来求图中每个点到起点的最短距离。

具体方法是,我们刚开始把除了1号点到起点的距离为1外,其他点到起点的距离都初始化为正无穷:

image.png

然后经过n次迭代,每次都把从距离起点最近的点推。现在1节点到起点的距离是0,2节点到起点的距离是1,3节点到起点的距离是4。表示如下:

image.png

我们接着推,2节点到3节点的距离是2,又因为2节点到1节点的距离是1,因此3节点到1节点的距离是3这条路径比3节点到1节点是4这条路径更短,节点3到起点的最短距离更新为节点2到起点的距离+节点3到节点2的距离=3

image.png

稠密图 邻接矩阵

849. Dijkstra求最短路 I - AcWing题库

n是500,m是1e5,总共就有500*1e5个点边,比较稠密,用邻接矩阵。

//稠密图  邻接矩阵
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int N=510;
int g[N][N];  //邻接矩阵
bool st[N];  //每个点的最短距离是否已经确定
int dist[N]; //每个点到起点的距离

int dijkstr()
{
    //初始化距离数组  因为求最短距离,所以要初始化为最大值
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;  //1号节点到起始点的距离是0
    
    //迭代n次
    for(int i=0;i<n;i++)
    {
        int t=-1;
        for(int j=1;j<=n;j++)
        {
          if(!st[j]&&(t==-1||dist[t]>dist[j]))  //如果t没有被确定为最近的路并且t不是最短的路 
          t=j;  //更新t为j     //更新
        }

         st[t]=true; //加入st里,表示t这条边已经确定为最短边
         for(int j=1;j<=n;j++)
         {
            dist[j]=min(dist[j],dist[t]+g[t][j]);   //更新一下1到j节点的最短距离
         }
        
    }
    //如果dist还是最大值说明不存在一条最短路,返回-1即可
    if(dist[n]==0x3f3f3f3f)return -1;
    return dist[n];
}

int main()
{
    memset(g,0x3f,sizeof g);  //邻接矩阵初始化
    
    cin>>n>>m;
    while(m--)
    {
        int a,b,c;cin>>a>>b>>c;
        g[a][b]=min(g[a][b],c);  //多条边里取较短的那条  
    }
    
    int t=dijkstr();
    cout<<t<<endl;
    return 0;
}

堆优化 邻接表

850. Dijkstra求最短路 II - AcWing题库

//稠密图  邻接矩阵
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
typedef pair<int,int>PII;
int n,m;
int h[N],e[N],ne[N],w[N],dist[N],idx;
bool st[N];
void add(int a,int b,int c)
{
    e[idx]=b;  //把b赋给边值e
    w[idx]=c;  //把距离给w  
    ne[idx]=h[a];  //头节点指针下一个指针
    h[a]=idx++; //头节点移到下一个节点
}




int dijkstr()
{   
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    
    priority_queue<PII,vector<PII>,greater<PII>> heap;
    heap.push({0,1});  //放入节点1,距离起点为0
    
    while(heap.size())
    {
        auto t=heap.top();  //每次取出距离分短的边
        heap.pop();
        
        int ver=t.second,distance=t.first;
        if(st[ver]) continue; //如果当前节点之前走过,说明冗余了,不用再处理当前节点
        
        
        
        
        for(int i=h[ver];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>distance+w[i])
             {
                 dist[j]=distance+w[i];
                 heap.push({dist[j],j}); 
             }
        }st[ver] = true;
    }


    
    if(dist[n]==0x3f3f3f3f)return -1;
    return dist[n];
}

int main()
{
    cin>>n>>m;
    

    //memset(dis,INF,sizeof dis); 
   memset(h,-1,sizeof h);  //初始化邻接表
   
    //读入m条边
    while(m--)
    {
        int x,y,z;cin>>x>>y>>z;
        add(x,y,z);
    }
    int t=dijkstr();
    cout<<t<<endl;
	return 0;
}