Dijkstra算法——計算一個點到其餘全部點的最短路徑的算法

迪傑斯特拉算法百度百科定義:傳送門html

gh大佬博客:傳送門node

迪傑斯特拉算法用來計算一個點到其餘全部點的最短路徑,是一種時間複雜度相對比較優秀的算法 O(n2)(相對於Floyd算法來講)ios

是一種單源最短路徑算法,可是它並不能處理負邊權的狀況算法

Dijkstra的算法思想:①將一開始全部的非源點到源的距離設置成無限大(你認爲的無限大其實是0x3f(int)或者0x7fffffff(long long)),而後源到源距離設置成0(不就是0嗎),而後每次找到一個距離源最短的點u,將其變成白點,枚舉全部的藍點,若是源到白點存在中轉站——一個藍點使得源->藍點和藍點->白點的距離和更短,就更新。②每找到一個白點,就嘗試更新其餘藍點,直到更新完畢。數組

代碼及註釋:優化

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<time.h>
#include<queue>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pr;
const double pi=acos(-1);
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define Rep(i,u) for(int i=head[u];i;i=Next[i])
#define clr(a) memset(a,0,sizeof a)
#define pb push_back
#define mp make_pair
#define fi first
#define sc second
ld eps=1e-9;
ll pp=1000000007;
ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
ll read(){
    ll ans=0;
    char last=' ',ch=getchar();
    while(ch<'0' || ch>'9')last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans;
    return ans;
}//快讀
//head



const int maxn=5001;
int g[maxn][maxn];//g數組用來存儲圖; 
int n,m,s;//分別表示點的個數、有向邊的個數、出發點的編號;
bool vis[maxn];//表示是否已經到達過;
int d[maxn];//d[i]表示從詢問點到點i的最短路徑;
const int inf=2147483647;

int main ()
{
    n=read(),m=read(),s=read();
    rep(i,1,n)
    {
        d[i]=inf;
        
        rep(j,1,n)
            g[i][j]=inf;
            
        g[i][i]=0;//本身到本身的最短路徑固然是0 
    }//初始化數組; 
    
    rep(i,1,m)
    {
        int u=read(),v=read(),w=read();
        //u,v,i分別表示第i條有向邊的出發點、目標點和長度;
        g[u][v]=w;//讀入; 
    }
    
    vis[s]=1;//將起點標記成已經到達;
    
    rep(i,1,n)
        d[i]=g[s][i];//將最短路徑初始化;
        //若是兩點之間有路線就初始化爲該距離,若是沒有就仍是inf;
        
    while(1)
    {
        int stt_node=0,stt_dis=inf;//stt=shortest 初始化兩個變量 
        // stt_node表示最短路徑的終點,stt_dis表示最短路徑的長度 
        
        rep(i,1,n)
        { 
            if(vis[i]==0&&d[i]<stt_dis)
            //若是該點尚未到達,而且他的距離小於最短距離 
            {
                stt_node=i,stt_dis=d[i];//更新變量 
            }
        }
        
        if(stt_node==0) break;
        //若是已經沒有能夠更新的最短路徑了,就說明已經結束了
        
        vis[stt_node]=1;//將該點標記成已經到達 
        
        rep(i,1,n)
        {
            if(vis[i]||g[stt_node][i]==inf)continue;
            //若是並無到達或者是兩點之間沒有路徑,就進入下一層循環 
            
            d[i]=min(d[i],stt_dis+g[stt_node][i]);//更新最短路徑 
        }
    }
    
    rep(i,1,n)
        printf("%d ",d[i]);
    return 0;
}

咱們考慮一下對它的優化。由於若是咱們每一次都要掃一遍判斷出邊,咱們還不如直接存出邊:spa

鄰接表!(鏈式前向星)

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<time.h>
#include<queue>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pr;
const double pi=acos(-1);
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define Rep(i,u) for(int i=head[u];i;i=Next[i])
#define clr(a) memset(a,0,sizeof a)
#define pb push_back
#define mp make_pair
#define fi first
#define sc second
ld eps=1e-9;
ll pp=1000000007;
ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
ll read(){
    ll ans=0;
    char last=' ',ch=getchar();
    while(ch<'0' || ch>'9')last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans;
    return ans;
}//快讀
//head


const ll INF = 2147483647;
struct edge
{
    ll to, dis_, next;
} Edge[9999999];
struct node
{
    ll to, dis;
    inline friend bool operator<(const node &a, const node &b)
    {
        return a.dis < b.dis;
    }
};
ll head[9999999], dis[9999999];
bool vst[9999999];
ll nodenum, edgenum, origin_node, cnt = 1, t;
priority_queue<node> q;

inline void add_edge(ll from, ll to, ll value)
{
    Edge[cnt].to = to;
    Edge[cnt].dis_ = value;
    Edge[cnt].next = head[from];
    head[from] = cnt++;
}

inline void dijkstra()
{
    for (register int i = 1; i < origin_node; i++)
    {
        dis[i] = INF;
    }
    //dis[origin_node]=0;
    for (register int i = origin_node + 1; i <= nodenum; i++)
    {
        dis[i] = INF;
    }
    q.push((node){origin_node, 0});
    while (!q.empty())
    {
        int x = q.top().to;
        q.pop();
        if (vst[x])
            continue;
        vst[x] = 1;
        for (register int i = head[x]; i; i = Edge[i].next)
        {
            dis[Edge[i].to] = min(dis[Edge[i].to], dis[x] + Edge[i].dis_);
            q.push((node){Edge[i].to, dis[Edge[i].to]});
        }
    }
}



int main()
{
    nodenum = read(), edgenum = read(), origin_node = read() ;//t=read();
    for (register int i = 1; i <= edgenum; i++)
    {
        register int f, t, v;
        f = read(), t = read(), v = read();
        add_edge(f, t, v);
    }
    dijkstra();
    rep(i,1,nodenum)
    {
        printf("%lld ",dis[i]);
    }
    
    return 0;
}
相關文章
相關標籤/搜索