zoukankan      html  css  js  c++  java
  • Dijkstra堆优化

    Dijkstra是一个非常不错的最短路算法,它使用两层循环进行枚举,通过每次更新蓝白点的方式更新最短路,时间复杂度为O(n^2),优于floyd的O(n^3),不过只能用于计算单源最短路,而且无法处理负权边。

    今天我们尝试用堆来优化它。这里我们使用了STL中的set和pair。set本身相当于一个小根堆,内部自动从小到大排序。(据说内部使用平衡树实现?蒟蒻瑟瑟发抖。)操作方式大致就是insert(插入)和erase(删除),不过他会把相同的数据融合到一起,如果不想这样可以使用multiset。对于堆的遍历我们不能像数组一样直接遍历,而是要使用迭代器。(用法下面代码有)而pair相当于一个有两个成员的且已经重定义的struct,使用makepair来新构造一个pair。

    具体怎么做呢?我们从起点出发,然后枚举每一条能走到的边(这里使用了邻接表存图),之后在选取最短的一条边时,我们使用堆即可,也就是将贪心变成了堆,这样时间复杂度就变为了O(nlogn)。

    直接上代码看一下就好啦!

    #include<cstdio>
    #include<vector>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<set>
    #include<map>
    #include<queue>
    #define mp make_pair
    #define fi first
    #define sc second
    #define faker(i,a,n) for(int i = a;i <= n;i++)
    #define duke(i,n,a) for(int i = n;i >= a;i--)
    const int M = 100001;
    int v[M],num,next[M],head[M],cost[M],dis[M];
    bool vis[M];
    int n,m,x,y,z;
    using namespace std;
    typedef pair<int,int> pr;//pair等于有两个成员且已经重定义的struct
    void add(int x,int y,int z)//邻接表存图
    {
        v[++num] = y;
        next[num] = head[x];
        cost[num] = z;
        head[x] = num;
    }
    int read()
    {
        int num = 0;
        char ch,last = ' ';
        ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-') last = ch;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            ans *= 10;
            ans += ch - '0';
            ch = getchar();
        }
        if(last == '-') ans = -ans;
        return ans; 
    }
    set<pr> q;//定义一个堆
    set<pr> :: iterator it;//迭代器定义
    int main()
    {
        n = read(),m = read();
        faker(i,1,m)//循环(不要问我为什么有这么奇怪的名字)
        {
            x = read(),y = read(),z = read();
            add(x,y,z);
        }
        faker(i,1,n) dis[i] = 1000000000;
        dis[1] = 0;
        q.insert(mp(dis[1],1));//将起点压入堆
        faker(i,1,n) vis[i] = 0;
        while(!q.empty())
        {
            pr u = *(q.begin());
            q.erase(q.begin());//删除堆顶元素
            vis[u.sc] = 1;//设置为走过
            for(int i = head[u.sc];i;i = next[i])
            {
                if(dis[v[i]] > dis[u.sc] + cost[i])
                {
                    it = q.find(mp(dis[v[i]],v[i]));
                    if(it != q.end())q.erase(it);//将当前较长的路径删除
                    dis[v[i]] = dis[u.sc] + cost[i];//更新距离
                    q.insert(mp(dis[v[i]],v[i]));//更新 ,压入更短的路径
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    js(5)关于this的指代值
    bootstrap(2)关于表单
    bootstrap(1)关于排版
    bootstrap基础(0)写在前面的一些话
    js(4) 继承
    js(3)面向对象的程序设计
    js(2)关于作用域和作用域链
    鼠标事件(jQuery方法)
    鼠标事件(JS原生方法)
    键盘事件(在输入框中输入内容后按回车键)
  • 原文地址:https://www.cnblogs.com/captain1/p/8552809.html
Copyright © 2011-2022 走看看