单元最短路dijkstra算法模板

朴素dijkstra算法模板:(针对稠密图)

注释:st数组为判断是否搜索过的数组,g[n][m]数组为邻阶矩阵,n和m分别指两条边(n指向m),g[n][m]对应的值就是n到m边的权重,数组dist[N]为存每个点到源点的最短距离。

上思路:

  1. 初始化所有点到源点的最短距离为正无穷(当然真正在实现时不会定义为无穷);

  1. 开始for循环n次,每次枚举一个点,循环结束,即可枚举完所有点,求到每个点到源点的最短距离。

  1. 在上一步的for循环里,再嵌套一层循环,从i=1开始循环,<=n,目的为寻找当前未被搜索过点里,里源点最近的点,且定义为t;

  1. 最后再用t点去更新其他点到源点的最短距离

上代码:

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=520,M=520;
int g[N][M],n,m;
bool st[N];
int dist[N];
int dijkstra()
{
    memset(dist,0x3f,sizeof dist);//初始化最短距离数组
    dist[1]=0;//定义第一个点的最短距离为0
    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=j;//j为目前离源点最近的点,并将t定义为j
        }
        st[t]=true;//标记已经搜索过
        for(int j=1;j<=n;j++)//利用t点去更新后面点到源点的最短距离
        dist[j]=min(dist[t]+g[t][j],dist[j]);
    }
    if(dist[n]==0x3f3f3f3f)return -1;
    else 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(c,g[a][b]);
    }
    cout<<dijkstra();
    return 0;
}

堆优化dijkstra求最短路(针对稀疏图)

思路:1.在原朴素版dijkstra基础上,主要变化是用堆(优先队列)来存储并遍历每一个点,而且要用邻接表来存图,因为这是稀疏图,此次要主要c++的优先队列(堆)默认是大根堆,这里需要定义为小根堆,操作为:priority_queue<PII,vector<PII>,greater<PII>>,且模板类似bfs框架。

​ 2.第一步初始化距离dist数组为无穷大。

​ 3.将源点入队,即head.push({0,1})0代表离源点最近的距离,1代表点的编号。

​ 4.接下来就是bfs模板(判断队列是否为空,然后取出对头元素,再删除队头元素。

​ 5.这里注意需要处理冗(rong)余备份,即我们还要一个用来判断这个点是否遍历过的一维数组st,如果st[i]=true,表示此点搜索过,为冗余备份,直接continue。

​ 6.接下来就是和朴素dijkstra一模一样的利用当前点去更新所有点到源点最短距离的步骤,不过这里多了一步,就是如果有一个点被处理过了就将这个点入队。

​ 7.还有就是用邻接表存的时候还有有一个专门存边的权重的数组,这里与普通邻接表有所不同,不过也好理解。

接下来上代码:

#include<iostream>

#include<cstring>

#include<queue>

#include<algorithm>

using namespace std;

const int N=150010;

int h[N],e[N],ne[N],idx;

int n,m,dist[N];

bool st[N];int w[N];

void add(int x,int y,int z)

{

e[idx]=y,ne[idx]=h[x],w[idx]=z,h[x]=idx++;

}

int dijkstra(){

priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> head;
memset(dist ,0x3f,sizeof dist);//初始化距离数组
dist[1]=0;
head.push({0,1});//先将源点入队
while(head.size())
{
    auto t=head.top();
    head.pop();
    int ver=t.second,distance=t.first;
    if(st[ver])continue;//处理冗余备份 
    st[ver]=true;
    for(int i=h[ver];i!=-1;i=ne[i])//用当前点来更新后面所有点
    {
        int j=e[i];
        if(dist[j]>dist[ver]+w[i])
        {
            dist[j]=dist[ver]+w[i];
            head.push({dist[j],j});
        }
    }
   
}
if(dist[n]==0x3f3f3f3f)return -1;
else return dist[n];

}

int main(){

cin>>n>>m;
memset(h,-1,sizeof h);
while(m--)
{
    int a,b,c;
    cin>>a>>b>>c;
    add(a,b,c);
}
cout<<dijkstra();
return 0;

}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值