Dijkstra求最短路(朴素做法与堆优化)

Dijkstra求最短路的基本思路是贪心算法,求解单源最短路。

适用于求解正权边。

算法的基本原理可以自行查看。

这里讲解两种求最短路的方法:

(1)、朴素算法

朴素算法的时间复杂度为O(n2),适用于稠密图,用邻接矩阵来存图,并且可以处理自环和重边。

Dijkstra求最短路 I

给定一个n个点m条边的有向图,图中可能存在重边和自环,所有边权均为正值。

请你求出1号点到n号点的最短距离,如果无法从1号点走到n号点,则输出-1。

输入格式

第一行包含整数n和m。

接下来m行每行包含三个整数x,y,z,表示存在一条从点x到点y的有向边,边长为z。

输出格式

输出一个整数,表示1号点到n号点的最短距离。

如果路径不存在,则输出-1。

数据范围

1≤n≤500      1≤n≤500,1≤m≤105     1≤m≤105,
图中涉及边长均不超过10000。

输入样例:

3 3
1 2 2
2 3 1
1 3 4

输出样例:

3
模板代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=510;
int n,m;
int q[N][N];
int d[N];
bool f[N];
int dj()
{
    memset(d,0x3f,sizeof d);
    d[1]=0;
    for(int i=0;i<n;i++)
    {
        int t=0;
        for(int j=1;j<=n;j++)
            if(!f[j]&&(t==0||d[t]>d[j])) t=j;
        f[t]=1;
        for(int j=1;j<=n;j++)
            if(!f[j]) d[j]=min(d[j],d[t]+q[t][j]);
    }
    if(d[n]==0x3f3f3f3f) return -1;
    return d[n];
}
int main()
{
    memset(q,0x3f,sizeof q);
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        q[a][b]=min(c,q[a][b]);
    }
    int k=dj();
    printf("%d\n",k);
    return 0;
}

(2)、堆优化算法

Dijkstra朴素算法只能处理变数较小的情况,当边数较多时间复杂度会变得特别大,邻接表所需空间也会很大。

这里就可以用到堆优化,堆优化主要适用于稀疏图(稠密图用也没问题),也可以处理自环和重边。

堆优化主要是用优先队列来实现,用邻接表存图(邻接表可以自己写或者直接用vector),时间复杂度为O(m log n )。

模板题:

Dijkstra求最短路 II

给定一个n个点m条边的有向图,图中可能存在重边和自环,所有边权均为非负值。

请你求出1号点到n号点的最短距离,如果无法从1号点走到n号点,则输出-1。

输入格式

第一行包含整数n和m。

接下来m行每行包含三个整数x,y,z,表示存在一条从点x到点y的有向边,边长为z。

输出格式

输出一个整数,表示1号点到n号点的最短距离。

如果路径不存在,则输出-1。

数据范围

1≤n,m≤1.5×1051≤n,m≤1.5×105,
图中涉及边长均不小于0,且不超过10000。

输入样例:

3 3
1 2 2
2 3 1
1 3 4

输出样例:

3
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N=1e5+10;
typedef pair<int,int> pii;
vector<pii>v[N];
int d[N];int n,m;
int dij()
{
    memset(d,0x3f,sizeof d);
    d[1]=0;
    priority_queue<pii,vector<pii>,greater<pii> >q;//给pii排序时先排fist 其次second 
    q.push({0,1});
    while(!q.empty())
    {
        pii t=q.top();
        q.pop();
        int ver=t.second,dis=t.first;for(int i=0;i<v[ver].size();i++)
        {
            pii y=v[ver][i];
            if(dis+y.first<d[y.second])
            {
               d[y.second]=dis+y.first;
               q.push({d[y.second],y.second});
            }
        }


    }
    if(d[n]==0x3f3f3f3f) return -1;
    return d[n];
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++)
    {
        int a,b,x;
        scanf("%d%d%d",&a,&b,&x);
        v[a].push_back({x,b});
    }
    int k=dij();
    printf("%d\n",k);
    return 0;
}

这里用pair来存1到id距离和id,优先队列默认以pair first从小到大排序。

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chp的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值