迪傑斯特拉算法(Dijkstra) (基礎dij+堆優化) BY:優少


首先來一段百度百科壓壓驚。。。

迪傑斯特拉算法(Dijkstra)是由荷蘭計算機科學家狄克斯特拉於1959 年提出的,因此又叫狄克斯特拉算法。是從一個頂點到其余各頂點的最短路徑算法,解決的是有權圖中最短路徑問題。迪傑斯特拉算法主要特點是以起始點為中心向外層層擴展,直到擴展到終點為止。

讓我來翻譯一下:
Dijkstra可以求出一個點到一個圖中其他所有節點的最短路徑,故也稱對於單源最短路徑的一種解法

算法實現步驟:

a.初始時,只包括源點,即S = {v},v的距離為0。U包含除v以外的其他頂點,即:U ={其余頂點},若v與U中頂點u有邊,則(u,v)為正常權值,若u不是v的出邊鄰接點,則(u,v)權值 ∞;
b.從U中選取一個距離v最小的頂點k,把k,加入S中(該選定的距離就是v到k的最短路徑長度)。

c.以k為新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改后的距離值的頂點k的距離加上邊上的權。

d.重復步驟b和c直到所有頂點都包含在S中。

動畫模擬:

 

 普通版Dijkstra代碼如下:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
int map[100][100];
int vis[100];
int way[100];
int n,e,w,s;
int main(){
    freopen("dij.in","r",stdin);
    freopen("dij.out","w",stdout);
       int i,j,x,y,z,w,mi=20000;
       scanf("%d%d",&n,&e);
       for(i=1;i<=e;i++)
       {
             scanf("%d%d%d",&x,&y,&z);
             map[x][y]=z;
             map[y][x]=z;
       }
       memset(way,127,sizeof(way));
       scanf("%d",&s);
       way[s]=0;
       for(i=1;i<n;i++)
       {
              for(j=1;j<=n;j++)
                  if(way[j]<mi&&vis[j]==0)
                  {
                        mi=way[j];
                        w=j;
                  }
              vis[w]=1;
              for(j=1;j<=n;j++)
                  if(map[w][j]!=0&&vis[j]==0&&way[j]>way[w]+map[w][j])
                     way[j]=way[w]+map[w][j];
       }
       for(i=1;i<=n;i++)
           printf("%d ",way[i]);
       return 0;
}

那現在讓我們分析一下復雜度,很明顯高達O(N*N),那當做一些題時不論內存還是時間都會爆,那就急需我們做一些優化了

Dijkstra的堆優化:

依舊是迪傑斯特拉算法的思想,尋找當前距離最小的點,然后將它標記為已經確定的點,用它來更新各個沒被確定的點。

emmmm我們選擇優先隊列來確定每一個最小距離的點

例題:【模板】單源最短路徑

代碼如下:

#include<bits/stdc++.h>
using namespace std;
struct SYM{
    int to,next,w;
}edge[500010];
struct LKJ{
    int v,c;
    bool operator <(const LKJ &a)const {
        return c>a.c;
    }
};
priority_queue<LKJ,vector<LKJ> > q;
int head[101000],vis[101000],tot,dis[101000],n,m,k;
void add(int x,int y,int w){
    edge[++tot].to=y;
    edge[tot].w=w;
    edge[tot].next=head[x];
    head[x]=tot;
}
void dij(int s){
     dis[s]=0;
     LKJ hh;hh.v=s;hh.c=0; 
     q.push(hh);
     while(!q.empty()){
         LKJ tmp=q.top();q.pop();
         int x=tmp.v;
        if(vis[x]) continue;vis[x]=1;
         for(int i=head[x];i;i=edge[i].next)
             if(!vis[edge[i].to]&&dis[edge[i].to]>dis[x]+edge[i].w){
                 dis[edge[i].to]=dis[x]+edge[i].w;
                 hh.v=edge[i].to;hh.c=dis[edge[i].to];
                 q.push(hh);
             }
    }
}
int main(){
    memset(dis,127,sizeof(dis));
    int x,y,w;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&w);
        add(x,y,w);
    }
    dij(k);
    for(int i=1;i<=n;i++){
        if(dis[i]==2139062143) printf("2147483647 ");
        else printf("%d ",dis[i]);
    }
    return 0;
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM