zoukankan      html  css  js  c++  java
  • Dijkstra

    最短路径

    dijkstra

    不可解决有负权的图

    但是若是没有负权的话,最好用这个,而不要用spfa,因为spfa的时间复杂度极其不稳定

    对于稀疏图来说,spfa的时间复杂度确实是要比dijkstra要低

    但,若是稠密图的话,spfa的时间复杂度就极其不可观了

    所以,dijkstra的重要性显然

    1.定义

        不可解决有负权边的图

        时间复杂度为O(n2)

        经过堆优化的dijkstra的时间复杂度为O(nlogn)

    2.算法描述

        贪心的思想(这是因为这个思想,所以判不出来负权边--(咳咳,个人之见,逃~)

        以起始点为中心向外层层扩展(广搜的思想),直到扩展到终点为止

    基本思想:

        引入两个集合S和U。

        S:记录已求出最短路径的顶点

        U:记录未求出最短路径的顶点

        (能到源点的所有点)

    操作:

        1.初始时,S集合中只包含源点s

             U集合中包含除s以外的其他顶点 且 U中顶点的距离为“起点s到该顶点的距离”

             (若相连,即为边权值;若不相连,则设其为无穷大)

        2.从U中选出“距离最短的顶点k”,将k加入s中,并将k从U集合中移出

        3.用新加入的顶点k来更新U集合中各个顶点到起点s的距离

         之所以更新U中顶点的距离,是因为 上一步中确定了k是求出最短路径的顶点,从而可以用k来更新其他的值

        4.重复2.3,直到遍历完所有点

    (假装已经会了)

    普普通通的dijkstra

    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    using namespace std;
    
    int map[110][110];//这就是map数组,存储图
    int dis[10010];//dis数组,存储估计值
    int book[10010];//book[i]代表这个点有没有被当做源点去搜索过,1为有,0为没有。这样就不会重复搜索了。
    int n,m;
    
    void dijkstra(int u)//主函数,参数是源点编号
    {
        memset(dis,88,sizeof(dis));//把dis数组附最大值(88不是十进制的88,其实很大)
        int start=u;//先从源点搜索
        book[start]=1;//标记源点已经搜索过
        for(int i=1; i<=n; i++)
        {
            dis[i]=min(dis[i],map[start][i]);//先更新一遍
        }
        for(int i=1; i<=n-1; i++)//源点不用 
        {
            int minn=9999999;//这里的minn不是题解上的minn,这代表的是最近点到源点的距离,start才代表最近的点、
            for(int j=1; j<=n; j++)
                if(book[j]==0 && minn>dis[j])
                {
                    minn=dis[j];
                    start=j;//找到离源点最近的点,然后把编号记录下来,用于搜索。
                }
            book[start]=1;
            for(int j=1; j<=n; j++)
                dis[j]=min(dis[j],dis[start]+map[start][j]);//以新的点来更新dis。
        }
    }
    
    int main()
    {
        cin>>n>>m;
        memset(map,88,sizeof(map)); 
        for(int i=1; i<=m; i++)
        {
            int a,b,c;
            cin>>a>>b>>c;
            map[a][b]=c;
        }//有向图吧 
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                if(i==j)
                    map[i][j]=0;//仅是初始化 
        dijkstra(1);//以1为源点。
        for(int i=1; i<=n; i++)
            cout<<dis[i]<<" ";
    }

     (普普通通的dij也几乎过不了什么,还得加上一个链式前向星)

    堆优化的dijkstra

    1.基本思想

    //堆优化dijkstra 边权不可为负 
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    using namespace std;
    
    inline int read()//快读 
    {
        int sum = 0,p = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '0')
                p = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            (sum *= 10) += ch - '0';
            ch = getchar();
        }
        return sum * p;
    }
    
    const int maxn = 1e5 + 5;
    const int maxm = 2e5 + 5;
    int n,m,s;//n为点的个数,m为变得个数,s为源点 
    int tot,dis[maxn],wei[maxm];//dis为i点到源点的距离,wei为边权 
    int head[maxn],to[maxm],nxt[maxm];//链式前向星 
    bool mrk[maxn];//标记该点是否被加入到最短路径的生成树中(0-没有,1-有) 
    priority_queue< pair<int,int> > q;
    /*
    优先队列:默认是大根堆
    pair第一维为dis[i]的相反数(这样就可以变成小根堆啦)
    第二维为节点编号 
    */
    
    void dijkstra()
    {
        memset(dis,0x3f,sizeof(dis));
        dis[s] = 0;//dis初始化 起点为0,其余为正无穷
        q.push(make_pair(0,s));
        while(q.size())
        {
            int x = q.top().second;
            q.pop();//取堆顶
            if(mrk[x])
                continue;
            mrk[x] = true;
            for(int i = head[x];i;i = nxt[i])
            {//扫描所有出边
                int y = to[i];
                int z = wei[i];
                if(dis[y] > dis[x] + z)
                {
                    dis[y] = dis[x] + z;
                    q.push(make_pair(-dis[y],y));
                }
            } 
        }
    }
    
    int main()
    {
        n = read(),m = read(),s = read();
        int x,y,z;
        for(int i = 1;i <= m;i++)
        {
            x = read(),y = read(),z = read();
            wei[++tot] = z;
            nxt[tot] = head[x];
            to[tot] = y;
            head[x] = tot;
        }//构建邻接矩阵 (通常可用add函数) 
        dijkstra();
        for(int i = 1;i <= n;i++)
            printf("%d ",dis[i]);
        return 0;
    }

    (我应该会回来补一补的qwq...)

        

        

        

  • 相关阅读:
    http
    node 学习 http
    socket.io
    每日日报
    每日日报
    每日日报
    06人件读书笔记之一
    每日日报
    每日日报
    05程序员修炼之道:从小工到专家阅读笔记之三
  • 原文地址:https://www.cnblogs.com/darlingroot/p/10554606.html
Copyright © 2011-2022 走看看