最短路的三种解法

最短路的三种解法

1.单源最短路
迪杰斯特拉(nn) 和 Spfa(nm)
一般使用迪杰斯特拉+堆优化,时间复杂度为(n+m)log2n,但是只用于不含有负权的边的求解最短
步骤:
1.建立边,dis数组无穷化,dis[start]=0;
2.优先队列加入边,当pr.dis != dis[pr.pos] 时continue,因为已经有更小的路径连接当前点了,所有不需要了
3.更新dis,并且push进去

优先队列排序的关键代码

bool operator < (const node &x)const
{
return x.dis < dis;
}

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int v,w,next;
} a[500010];
struct nodee
{
    int dis,pos;
    bool operator < (const nodee &x)const
    {
        return x.dis <dis;
    }
};
priority_queue<nodee>q;
int head[100010];
int dis[100010];
int tot = 0;
const int inf = 1e9+7;
int n;
void dj(int s)
{
    dis[s] = 0;
    nodee e;
    e.dis = 0;
    e.pos = s;
    q.push(e);
    while(!q.empty())
    {
        nodee fr = q.top();
        q.pop();
        int now = fr.pos;
        int len = fr.dis;
        if(dis[now]!=len)continue;
        for(int j = head[now] ; j != 0; j = a[j].next)
        {
            int y = a[j].v;
            int z = a[j].w;
            if(dis[y] >dis[now] + z)
            {
                dis[y] = dis[now] + z;
                nodee temp;
                temp.pos = y;
                temp.dis = dis[y];
                q.push(temp);
            }
        }
    }
};
int main()
{
    int m,s;
    scanf("%d%d%d",&n,&m,&s);
    for(int i=1; i<=n; i++)
    {
        head[i] = 0;
        dis[i]=inf;
    }
    for(int i=1; i<=m; i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        ++tot;
        a[tot].v = y;
        a[tot].w = z;
        a[tot].next = head[x];
        head[x] = tot;
    }
    dj(s);
    for(int i = 1; i <= n; i++)
    {
        printf("%d ",dis[i]);
    }
    printf("\n");
}

Spfa
使用队列bfs,vis数组看当前点是否在队列中,如果dis[y] > dis[k] + z &&不在队列中,就加入并且使它标记为1

#include<bits/stdc++.h>
#define sc scanf
#define pr printf
using namespace std;
const int inf=2147483647;
int vis[10010];
int dis[10010];
struct node{
int to;
int z;
int next;
}a[500010];
int head[10010];
queue<int>q;
void spfa(int s){
dis[s]=0;
q.push(s);
vis[s]=1;
while(!q.empty()){
    int now=q.front();
    vis[now]=0;
    q.pop();
    for(int i=head[now];i!=-1;i=a[i].next){
        int to=a[i].to;
        int z=a[i].z;
        if(dis[to]>dis[now]+z){
            dis[to]=dis[now]+z;
            if(!vis[to]){
                vis[to]=1;
                q.push(to);
            }
        }
    }
}
}
int main(){
int n,m,s;
sc("%d%d%d",&n,&m,&s);
for(int i=1;i<=n;i++){
    head[i]=-1;
    dis[i]=inf;
    vis[i]=0;
}
int top=0;
for(int i=1;i<=m;i++){
    int u,v,w;
    sc("%d%d%d",&u,&v,&w);
    a[top].next=head[u];
    a[top].to=v;
    a[top].z=w;
    head[u]=top;
    top++;
}
spfa(s);
for(int i=1;i<=n;i++){
    printf("%d ",dis[i]);
}
printf("\n");
return 0;
}

多源最短路
佛洛依德
思路就是 我假如要从i到j,要使更短我们就要借助中间的一个点k是的i->k->j的路程小于i->j
关键代码
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(dis[i][k]+dis[k][j]<dis[i][j]){
dis[i][j] = dis[i][k] +dis[k][j];
}
}
}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值