把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

Dijkstra及其队列优化

设计背景

    Edsger Wybe Dijkstra
    荷兰人
    1972 Turing Award,
    结构化程序设计语言之父,
    成就有 goto有害论, Dijkstra算法。

过程模拟

  • 定义集合P为已求出最短路径的顶点, Q为未求出最短路径的顶点

  • 设起点为s,dis[v]表示从s到v的最短路径, pre[v]为v的前驱节点,用来输出路径。

  • 初始化:

    dis[v]=∞(v≠s);dis[s]=0; pre[s]=0;

    for (i = 1; i <= n ; i++)

    1.在集合Q中找一个顶点u使得dis[u]最小

    2.u标记为已确定最短路径,从Q中删除,加 入P中

    3.for 与u相连的每个顶点v

    if(dis[u]+w[u][v]<dis[v]) { 
        dis[v]=dis[u]+w[u][v];pre[v]=u; 
    }
  • 结束:dis[v]为s到v的最短距离;

   pre[v]为v的前驱,用来输出路径。

(有图有真相)

          以0点为源点,dist[i]为源点到顶点的最短路径。
步骤dist[1]dist[2]dist[3]dist[4]已找到的集合
第一步 8 1 2 +∞ {2}
第二步 8 1 2 4 {2,3}
第三步 5 1 2 4 {2,3,4}
第四步 5 1 2 4 {2,3,4,1}

由于老韩在课上讲到了**质疑**的重要性!

那么


Emotion。发现你可能存在以下疑问

若A作为源点,与其邻接的只有B,C,D三点,

其dist[]最小时顶点为C,即就可以确定A→C为A到C的最短路。

但是我们存在疑问的是:是否还存在另一条路径使A到C的距离更小? 

用反证法证明。

假设存在如上图的红色虚线路径,
使A→D→C的距离更小,
那么A→D作为A→D→C的子路径,
其距离也比A→C小,
这与前面所述“dist[]最小时顶点为C”矛盾,
故假设不成立。
因此这个疑问不存在。 根据上面的证明,
我们可以推断出,
Dijkstra每次循环都可以确定一个顶点的最短路径,
故程序需要循环n-1次。
(该部分内容借鉴大佬博客qwq)

完整代码

(这是一份喜欢卖萌的代码qwq)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
//#include<qwq> 

#define INF 0x3fffffffffffffff
#define ll long long
#define maxn 10010
//#define QAQ qwq
using namespace std;

ll dis[maxn];                        //result
bool v[maxn];                     //访问与否 
int n,m,s;                        //n:
//int QVQ;
struct my_pair
{
    int v;                 //to
    ll d;                                 //data
    my_pair(int x,ll y)
    {
        v=x;
        d=y;                        //初始化 
    }
    bool operator < (my_pair r/*right*/) const
    {
        return d>r.d;
    }                            //运算符重载 
};
//struct QVQ
struct Edge
{
    int to,next;                                        //to=go,next=from
    ll val;                                                 //data
}E[maxn*2];

int cnt;
int h[maxn];                  //head

void add(int u,int v,ll d)
{
    E[++cnt].to=v;
    E[cnt].val=d;
    E[cnt].next=h[u];
    h[u]=cnt;
}

void dijkstra(int x)
{
    memset(v,0,sizeof(v));                                        //将v数组初始化,使得里面没有点 
    for(int i=1;i<=n;i++)
        dis[i] = (i==x) ? 0 : INF;                        //将源点存储,标记权值为0 
    priority_queue <my_pair> pq;     
    pq.push(my_pair(x,dis[x]));                        //将x,dis【x】存入my_pair对象中 

    while(!pq.empty())
    {
        int r=pq.top().v;                                //search 顶点 
        ll rdis=pq.top().d;            //search data
        pq.pop();                                            //弹出第一个点 
        if(v[r])
            continue;                                    // 访问过的点拒绝访问 
        else
            v[r]=true;                            //立flag标记访问与否
        for(int i=h[r];i;i=E[i].next)   //从顶点访问到完 
        {
            int y=E[i].to;       //y点是这条边到达的点
            if(rdis+E[i].val<dis[y])
            {
                dis[y]=rdis+E[i].val;
                pq.push(my_pair(y,dis[y]));
            } 
        }
    } 
}
//int main QAQ
int main()
{
    cout<<"q请输入点数:"<<endl; 
    cin>>n;                                
    cout<<"w请输入边数:"<<endl;
    cin>>m;
    cout<<"q请输入起点:"<<endl;
    cin>>s; 
    cout<<"QAQ请输入每条边的两点及权值:"<<endl;
    for(int i=1;i<=m;i++)
    {
        int u,v;
        ll d;
        cin>>u>>v>>d;
        add(u,v,d);
        add(v,u,d);
    } 
    dijkstra(s);
    cout<<"Orz这是结果:"<<endl; 
    for(int i=1;i<=n;i++)
        cout<<"1->"<<i<<" "<<dis[i]<<endl;
    return 0;
}

 

结果表示:

时间复杂度

众所周知,Dijkstra算法的时间复杂度为

而Dijkstra在优先队列的的优化下时间复杂度可达O(nlogn)O(nlogn)O(nlogn);

(毕竟Emotion。对时间复杂度的计算有些问题,所以就说这么多啦qwq)


emmm

就这么结束吧

真是不敢相Emotion的第一篇博客是关于Dijkstra的QAQ

最后附上大佬博客qwq大佬在这里!

posted @ 2019-02-17 16:19  Emotion。  阅读(509)  评论(0编辑  收藏  举报