图论算法----最短路径SPFA算法详解

来源:互联网 发布:sqlserver backup log 编辑:程序博客网 时间:2024/05/21 14:07

一、题目描述

SPFA算法

题目描述

有向图的单源点最短路径问题。源点编号为1,终点编号为n。

输入

第1行:2个空格分开的整数n(2<=n<=5000)和m(10<=m<=500000),分别表示图的顶点数和边数。

第2..m+1行:每行3个空格分开的整数i,j, w。i表示一条边的起点,j表示终点, w表示权值。

输出

第1行:1个整数,表示最小距离

样例输入

样例1:4 71 2 681 3 191 4 662 3 233 4 653 2 574 1 68样例2:3 31 2 -72 3 43 1 2

样例输出

样例1:66样例2:No Solution


二、算法分析

在看算法分析时,请保证自己对题目已经十分熟悉)


该算法比较复杂,需要读者具有一定的基础,了解队列的一些用法)



这种题目是典型的最短路径问题,可以用许多算法来解决,但是看了数据范围之后......只有SPFA能够解决。

知道了用SPFA算法, 那我们就来看看SPFA的思路

SPFA是Bellman-Ford的升级版,因为Bellman-Ford里有许多不必要的计算,所以SPFA就利用队列来进行了时间复杂度的优化。

SPFA算法全过程:

1、将起点加入队列,while循环开始。

2、从队列中取出一个元素,for循环开始。

3、用它的最短路径来更新与它相邻的点最短路径,如果有更新成功的,就将其入队

4、for循环结束

5、当队列为空时,while循环结束。

时间复杂度为O(kE),k为常数,大约为2,E为边数,一个接近完美的算法。

算法的总体结构有点像BFS(广搜),但是SPFA中不会判重,就是一个点有可能会多次入队。

看起来SPFA的思路很简单,但是实践起来就不同了。


三、题目分析

(在看题目分析时,请大家做好心理准备


看完题目后,相信大家对程序的框架已经搭好了,大概是这样的:

初始化+SPFA+负权回路判断

但是仔细一看,这些都是难点。

1、初始化:

(1)、将dis数组清为最大值,dis[1]=0;

(2)、将输入的边进行排序(写cmp函数)

(3)、计算每一个点的出边数和对应的起始位置,为SPFA做准备

2、SPFA

(1)、取出一个点

(2)、判断是否有出边

(3)、进行连接点最短路径的更新

3、负权回路判断

这个比较简单,用一个pd数组,一个点入队一次就pd[该点编号]++,

如果超过了pd[该点编号]总点数,就输出“No Solution”。

AC代码:

#include<cstdio>#include<algorithm>#include<cstring>#include<queue>using namespace std;queue <int > q;int dis[5005],out[5005][2],n,m,pd[5005];struct node{    int cd,s,t;}w[500005];bool cmp(node a,node b){    if(a.s<b.s) return 1;    else if(a.s>b.s) return 0;    else if(a.t<b.t) return 1;    else return 0;}int main(){    int i,u;    scanf("%d%d",&n,&m);    memset(dis,1,sizeof(dis));    for(i=1;i<=m;i++){        scanf("%d%d%d",&w[i].s,&w[i].t,&w[i].cd);        out[w[i].s][1]++;    }    sort(w+1,w+n+1,cmp);    q.push(1);    dis[1]=0;    out[1][0]=1;    for(i=2;i<=n;i++)        out[i][0]=out[i-1][0]+out[i-1][1];    while(!q.empty()){//SPFA        u=q.front();        q.pop();        if(out[u][1]!=0){            for(i=out[u][0];i<=out[u][0]+out[u][1]-1;i++){                if(dis[u]+w[i].cd<dis[w[i].t]){                    dis[w[i].t]=dis[u]+w[i].cd;                    q.push(w[i].t);                    pd[w[i].t]++;//pd                    if(pd[w[i].t]>n){                        printf("No Solution");                        return 0;                    }                }            }        }    }    printf("%d",dis[n]);}



 

1 0
原创粉丝点击