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); 
        
    }
  • 相关阅读:
    java中的 equals 与 ==
    String类的内存分配
    SVN用命令行更换本地副本IP地址
    npoi 设置单元格格式
    net core 微服务框架 Viper 调用链路追踪
    打不死的小强 .net core 微服务 快速开发框架 Viper 限流
    net core 微服务 快速开发框架 Viper 初体验20201017
    Anno 框架 增加缓存、限流策略、事件总线、支持 thrift grpc 作为底层传输
    net core 微服务 快速开发框架
    Viper 微服务框架 编写一个hello world 插件02
  • 原文地址:https://www.cnblogs.com/dancer16/p/6964454.html
Copyright © 2011-2022 走看看