算法基础 - 单源点最短路径SPFA

来源:互联网 发布:软件测试经典案例 编辑:程序博客网 时间:2024/06/06 09:06

SPFA是非常简单的最短路径算法,思想就是从起点开始,进行宽度优先搜索,不断松弛S点到其他相邻点的距离。如果松弛了点B,则把点B放到队列里。假如点B已经在队列里了,就不要放了,判断在不在队列可以用个数组来表示。

引用一段hihocoder上的解释:

构造一个队列,最开始队列里只有(S, 0)——表示当前处于点S,从点S到达该点的距离为0,然后每次从队首取出一个节点(i, L)——表示当前处于点i,从点S到达该点的距离为L,接下来遍历所有从这个节点出发的边(i, j, l)——表示i和j之间有一条长度为l的边,将(j, L+l)加入到队尾,最后看所有遍历的(T, X)节点中X的最小值就是答案咯~”小Ho对于搜索已经是熟稔于心,张口便道。
SPFA算法呢,其实某种意义上就是宽度优先搜索的优化——如果你在尝试将(p, q)加入到队尾的时候,发现队列中已经存在一个(p, q')了,那么你就可以比较q和q’:如果q>=q',那么(p, q)这个节点实际上是没有继续搜索下去的必要的——算是一种最优化剪枝吧。而如果q < q',那么(p, q')也是没有必要继续搜索下去的——但是它已经存在于队列里了怎么办呢?很简单,将队列中的(p, q')改成(p, q)就可以了!”

“那我该怎么知道队列中是不是存在一个(p, q')呢?”
维护一个position[1..N]的数组就可以了,如果不在队列里就是-1,否则就是所在的位置!”

“所以说这本质上就是宽度优先搜索的剪枝咯?”小Ho问道。
小Hi笑道:“怎么可能!SPFA算法其实是BELLMAN-FORD算法的一种优化版本,只不过在成型之后可以被理解成为宽度优先搜索的!这个问题,我们会在之后好好讲一讲的!

代码如下:

#include <iostream>#include <cstring>#include <string>#include <queue>using namespace std;struct Node{    int val;    int len;    Node * next;    Node():val(-1),len(-1), next(NULL){}    Node(int x, int le): val(x), len(le), next(NULL){}};long long SPFA(Node node[], int M, int S, int T){    queue<int> st;    st.push(S);    int flag[M+5];    long long dist[M+5];    for(int i = 0; i < M+5; i++){        flag[i] = 0;        dist[i] = -1;    }    dist[S] = 0;    flag[S] = 1;    while(!st.empty()){        int cur = st.front();        st.pop();        flag[cur] = 0;        Node * temp = node[cur].next;        while(temp != NULL){            if(dist[temp->val] == -1 || dist[temp->val] > (dist[cur]+temp->len)){                dist[temp->val] = dist[cur]+temp->len;                if(flag[temp->val] == 0){                    st.push(temp->val);                    flag[temp->val] = 1;                }            }            temp = temp->next;        }    }    return dist[T];}int main(){    int M,N,S,T;    // M 顶点个数, N 边个数, S起点, T 终点    while(cin>>M>>N>>S>>T){        Node node[M+5];        int st, en, le;        for(int i = 0; i < N;i++){            cin>>st>>en>>le;            //st边起点 en边终点 le边长度            Node * temp = new Node(en,le);            temp->next = node[st].next;            node[st].next = temp;            /*如果是无向图加上这三条语句            temp = new Node(st,le);            temp->next = node[en].next;            node[en].next = temp;            */        }        cout<<SPFA(node, M, S, T)<<endl;    }}

大致如上

1 0
原创粉丝点击