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

    dijkstra是一种单元最短路径算法,其能在较好时间复杂度内处理这一问题。但其对负权圈的处理让人不太满意——会陷入死循环

    其思想和Prim算法差不多,都是贪心。

    把图中的所有点划分为两个集合:包含远点S和不包含原点S的

    每次从不包含原点S的集合中找出一个离原点S最近的点(这样就没有点能够比这个点更加接近原点,这也是其不能处理负权边的原因)

    我们先考虑简单一点的情况:没有负权边

    设u是不包含s中dist最小的那个点,另外v是不包含S中的任意点

    如果v能更新u点<==>dist[v]+map[v][u]<dist[u];因为map[v][u]>0所以有dist[v]<dist[u]假设不成立

    所以我们就有一个算法啦

    1.每次找出不包含S中最近点,加入包含s的集合

    2.维护所有和这个店相连的不在包含s的集合里的点到原点的距离(Prim维护的是到包含S的集合的距离)

    时间复杂度Θ(n^2)比较优,适合稠密图。

    但我们发现每次找一个最近点有点耗时,因为要支持减值和求最小的操作,就用优先队列啦

    (优先队列在小根堆情况下支持降值,大根堆下支持升值)但优先队列里的元素有O(E)个开空间时需注意~~

    上代码~

    转自HK大神的blog,对于重载()不是很懂

    #include<iostream>
    #include<cstdio>
    #include<queue>
    using namespace std;
    int n,m,S,tot,Next[500010],head[20000],tree[500010],val[500010];
    bool visit[20000];
    long long dis[20000];
    struct cmp
    {
        bool operator()(int a,int b)
        {
            return dis[a]>dis[b];
        }
    };
    priority_queue<int,vector<int>,cmp> Q;
    void add(int x,int y,int z)
    {
        tot++;
        Next[tot]=head[x];
        head[x]=tot;
        tree[tot]=y;
        val[tot]=z;
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&S);
        tot=0;
        for (int i=1;i<=m;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            if (x==y) continue;
            add(x,y,z);
        }
        for (int i=1;i<=n;i++) 
        {
            visit[i]=false;
            dis[i]=2147483647;
        }
        Q.push(S);
        dis[S]=0;
        while (!Q.empty())
        {
            int u=Q.top();
            Q.pop();
            if (visit[u]) continue;
            visit[u]=true;
            for (int i=head[u];i;i=Next[i])
            {
                int v=tree[i];
                if (!visit[v]&&dis[v]>dis[u]+(long long)val[i])
                {   
                    dis[v]=dis[u]+val[i];
                    Q.push(v);
                }
            }
        }
        for (int i=1;i<=n-1;i++) printf("%lld ",dis[i]);
        printf("%lld
    ",dis[n]);
        return 0;
    }

     下面自己写的,渣~(我会告诉你我懒

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #define N 2000005
    using namespace std; 
    int n,m,s,next[N],to[N],head[N],vis[N],cos[N],dis[N],num=0,u,v,c;
    struct note{
        int to,cos;
    };
    struct cmp
    {
         bool operator()(int a,int b)
         {
            return dis[a]>dis[b];
        }
    };
    priority_queue<int,vector<int>,cmp> Q;
    void push_way(int u,int v,int c)
    {
        to[++num]=v;
        cos[num]=c;
        next[num]=head[u];
        head[u]=num;
    }
    void dijkstra(int s)
    {
        Q.push(s);
        //vis[s]=1;
        dis[s]=0;
        while(!Q.empty())
        {
            int u=Q.top();
            Q.pop();
            if(vis[u]) continue;
            cout<<u<<endl;
            vis[u]=1;
            for(int i=head[u];i;i=next[i])
            {
                int v=to[i];
                if(!vis[v]&&dis[v]>dis[u]+cos[i])
                {
                    dis[v]=dis[u]+cos[i];
                    Q.push(v);
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            cout<<dis[i]<<' ';
        }
        cout<<endl;
    }
    int main()
    {
        scanf("%d %d %d",&n,&m,&s);
        for(int i=1;i<=n;i++)
        dis[i]=10000;
        for(int i=1;i<=m;i++)
        {
            scanf("%d %d %d",&u,&v,&c);
            push_way(u,v,c);
        }
        dijkstra(s); 
        
    }
  • 相关阅读:
    arm单板上移植gdb
    video on web
    chromium源码阅读
    CE-HTML简介
    multi-tap
    DPDK 网卡RSS(receive side scaling)简介
    c语言实现带LRU机制的哈希表
    Linux TCP协议使用的变量
    scp源码浅析
    Linux e1000e网卡驱动
  • 原文地址:https://www.cnblogs.com/dancer16/p/6964454.html
Copyright © 2011-2022 走看看