zoukankan      html  css  js  c++  java
  • Dijkstra算法——计算一个点到其他所有点的最短路径的算法

    迪杰斯特拉算法百度百科定义:传送门

    gh大佬博客:传送门

    迪杰斯特拉算法用来计算一个点到其他所有点的最短路径,是一种时间复杂度相对比较优秀的算法 O(n2)(相对于Floyd算法来说)

    是一种单源最短路径算法,但是它并不能处理负边权的情况

    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;
    }

    我们考虑一下对它的优化。因为如果我们每一次都要扫一遍判断出边,我们还不如直接存出边:

    邻接表!(链式前向星)

    #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;
    }

     

     

  • 相关阅读:
    配置文件中文件重复
    大型网站技术架构02
    2018.12.26-12.30第一周毕设计划
    软件架构模式-分层架构II
    软件架构模式-分层架构
    echarts实现中国地图数据展示
    Python数据分析入门(一)——了解Python下的函数包
    Python学习笔记(二)
    Python学习笔记(一)
    Echarts的简单使用
  • 原文地址:https://www.cnblogs.com/lcezych/p/10739866.html
Copyright © 2011-2022 走看看