最短路 dijkstra

(1)dijkstra

N个节点,循环N次,每次循环取出当前未确定最短路径的最小值ind,确定其为最短路径,并把ind可到达的节点更新。


#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;

struct Node {

    int v, dist;

};
const int MAXN = 100010,inf=0x7fffffff;
vector <Node> G[MAXN];
 int m, N;
 int vis[MAXN],d[MAXN];
 int pre[MAXN]; 

 void dijkstra(){
        memset(vis, 0,sizeof(vis));
        d[1]=0;
        for(int i=2;i<=N;i++) d[i]=inf;

        int ind=0;
        for(int i=0;i<N;i++){
            int _min=inf;
            for(int j=1;j<=N;j++) 
                if(vis[j]==0&&_min>d[j]){
                    _min=d[j];
                    ind=j;
                }


            if(_min==inf) 
                break;
            vis[ind]=1;
            for(int k=0;k<G[ind].size();k++){
                int v=(int)G[ind][k].v;
               if(v!=-1&&d[ind]+(int)G[ind][k].dist<d[v]){
                    d[v]=d[ind]+(int)G[ind][k].dist;
                    pre[v]=ind;
                }
            }

        }
    }

int main(){

  freopen("data","r",stdin);
  freopen("data.out1","w",stdout);
    while(cin>>N>>m){

        for(int i=0;i<MAXN;i++){
            G[i].clear();
        } 
      memset(vis,0,sizeof(vis));
    for (int i=1;i<=m;i++)
    {
        int from,to,dist;
        scanf("%d%d%d",&from,&to,&dist);
        G[from].push_back((Node){to,dist});
        G[to].push_back((Node){from,dist});
    }
        dijkstra();
        cout<<d[N]<<endl;
    }
}

输入:
5 7

1 2 8

1 4 10

2 3 9

2 4 10

2 5 1

3 4 7

3 5 10

输出:
9

(2)优先队列优化的dijkstra
先上代码:

 void dijkstra_queue(){
         priority_queue< Node>pq;
        pq.push((Node){1,0});
        memset(vis,0,sizeof(vis));
        vis[1]=1;
        d[1]=0;
        for(int i=2;i<=N;i++) d[i]=inf;

        while(!pq.empty()){
            int ind=(int)pq.top().v;
            pq.pop();
            vis[ind]=1;
            cout<<"出队元素"<<ind<<endl;
             cout<<"入队元素"; 
            for(int k=0;k<G[ind].size();k++){
                int v=(int)G[ind][k].v;
                if(v!=-1&&d[v]>d[ind]+(int)G[ind][k].dist){
                    d[v]=d[ind]+(int)G[ind][k].dist;
                        pre[v]=ind;
                    if(!vis[v]){
                     vis[v]=1;
                     cout<<v<<",";
                     pq.push((Node){v,d[v]});

                    }



                }
            }
        cout<<endl;
            for(int i=1;i<=N;i++) cout<<d[i]<<",";
            cout<<endl;
        }

    }

将每次取出的最短距离放入一个优先队列,每次从优先队列中取出
队首元素ind,对它所到达的节点进行更新。

然而这会造成多个相同节点 在队列中,但是这样带来的问题是,队列中间消耗可能会很大。这里是个坑,需要详细讲解,看下图:
这里写图片描述
首先从 1 开始

队列 1
dis 0

队列 2 4 3
dis 5 15 17

2 出队,更新

队列 4 3
dis 15 11
接下来出队的是3么?很遗憾,并不是想象中的3,请看打印结果:
这里写图片描述

为什么是4呢?

只有在对队列进行操作的时候(push 、pop),才会改变队列结构。
优先队列不是一个服务器,随时都在监测这你的 d 数组有没有值的改动。
这里面涉及到 stl 优先队列的实现,很多细节上的东西我们无从而知。
要想达到我们取出3的效果,就需要把更新过的3重新入队。

代码如下:

    void dijkstra_queue2(){
        priority_queue< Node>pq;
        pq.push((Node){1,0});

        d[1]=0;
        for(int i=2;i<=N;i++) d[i]=inf;

        while(!pq.empty()){
            int ind=(int)pq.top().v;
            pq.pop();
            cout<<"出队元素"<<ind<<endl;
            cout<<"入队元素"; 
            for(int k=0;k<G[ind].size();k++){
                int v=(int)G[ind][k].v;
                if(v!=-1&&d[v]>d[ind]+(int)G[ind][k].dist){
                    d[v]=d[ind]+(int)G[ind][k].dist;
                        pre[v]=ind;
                        pq.push((Node){v,d[v]});
                             cout<<v<<",";
                }
            }
            cout<<endl;
            for(int i=1;i<=N;i++) cout<<d[i]<<",";
            cout<<endl;
        }

    }

打印结果:
这里写图片描述

事实上这样 用priority queue 意义并不大。最好的方式是用堆优化dijkstra,可以每次主动去自己调整堆的结构。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值