堆(优先队列)优化dijkstra(邻接矩阵)

上篇博客大家学习了最短路的两种基本算法,忘了告诉大家,floyd可以完成有负权值的最短路,而dijkstra则不行。若要想要更优的进行负权值最短路,请期待我的SPFA详解。

现在开始堆优化dijkstra的讲解。

其实只要理解了dijkstra的本质,这也就不难了,就是把查询最小dis值的过程用堆实现即可。具体代码如下:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>

using namespace std;

int n,num,tree[10000][10],map[1000][1000],book[1000],dis[1000],m,i,j,mini,u;

void swap(int x,int y){//堆操作 
    int t;
    t=tree[x][1];
    tree[x][1]=tree[y][1];
    tree[y][1]=t;
    t=tree[x][2];
    tree[x][2]=tree[y][2];
    tree[y][2]=t;
}
void siftdown(int i){//堆操作 
    int t,flag=0;
    while (i*2<=n&&flag==0){
        t=i;
        if (tree[i][1]>tree[i*2][1]) t*=2;
        if (i*2+1<=n){
            if (tree[t][1]>tree[i*2+1][1]){
                t=i*2+1;
            }
        }
        if (i!=t){
            swap(i,t);
            i=t;
        }
        else flag=1;
    }
}

void build(){//堆操作 
    int i;
    for (i=trunc(n/2);i>=1;--i) siftdown(i);
}

int posh(){
    int t;
    t=tree[1][1];
    tree[1][1]=tree[n][1];
    n--;
    siftdown(1);
    return t;
}
int main(){
    scanf("%d%d",&num,&m);
    n=num;
    for (i=1;i<=n;++i) 
     for (j=1;j<=n;++j){
        i==j?map[i][j]=0:map[i][j]=21474836;
     }
    for (i=1;i<=m;++i){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        map[x][y]=z;
        map[y][x]=z;
    }
    for (i=1;i<=num;++i){
        dis[i]=tree[i][1]=map[1][i];
        tree[i][2]=i;
        book[i]=0;
    }
    build();
    book[1]=1;
    mini=posh();
    for (i=1;i<=num-1;++i){
        u=tree[1][2];mini=posh();//堆代替for循环 
        book[u]=1;
        for (j=1;j<=num;++j){
            if (dis[j]>dis[u]+map[u][j]){
                dis[j]=map[u][j]+dis[u];
            }
        }
    }
    printf("%d",dis[num]);
}

下次,我将发表关于最小生成树算法的博客,请大家继续关注,靴靴。。。。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值