[Template] SPFA (not fully explain)

One of the most short-circuit evaluation method (personal feel than DIJKSTRA easy to use)     

Directed to FIG.

Probably thinking: starting from the root, enumerate every point, while the shortest path to their updated Unicom's point, if the path is updated, put this point into the team, repeating this operation until the team is up empty.  

Code:

struct Edge {
     int Next, to, V; 
} E []; // save FIG, next node on behalf of the same head of the next edge 

void SPFA ( int S) {
     int P, X, Y, L, R & lt;
     for ( = X . 1 ; X <= n-; ++ X) 
        DIS [X] = INF; 
    Q [ 0 ] = S, DIS [S] = 0 , V [S] = . 1 ; // initialization 
    for (L = R & lt = 0 ; L = (R & lt +! . 1 )% N;) { 
        P = Q [L], ++ = L% N; // takes out the first team 
        for(X = First [P]; X; X = E [X] .next) // traverse the head of the queue with the head of each side 
            IF (DIS [P] + E [X] .v <DIS [(Y = E [X] .to)]) { // If the update 
                DIS [Y] = DIS [P] + E [X] .v; // update 
                IF ! ( V [Y]) { 
                    V [Y] = . 1 ; 
                    Q [ ++ = N R & lt%] = Y; // enqueue 
                } 
            } 
        V [P] = 0 ; 
    } 
}

But this approach can easily be stuck out (the magic cow), so SLF optimization can be used.

SLF optimization: Every time the team was going to regard the value of the team's first value comparison, if the value is less than the first team, then into the first team.

why?

Because every time there will be traversing from the first team when the team first is the minimum value is updated so the node will be the minimum, this can save a large part of the time.

(Somewhat abstract .. To give an example)

(I do not want to draw)

 

这里需要注意:只有dis[]存储路径值,q[]存储的是当前最小路径值所在的位置,包括edge里的next也是同一个起点的上一对点的序号。(这里的头就是First[]的下标)

这里各种各样的序号很多。。特别容易弄混。会把各种序号分段输出的程序放在结尾,看不懂的话试几组样例看看输出会很有帮助。

到这里只是第一次更新。

下面是第二次更新:

 

接下来就可以以此类推了。。如果看不懂的话下面是分段输出的代码,结合上面的图看,体会一下中心思想。

代码

#include<iostream>
using namespace std;
struct edge {
    int next, to, v;
    edge(){}
    edge(int x,int y,int z)
    {
        next=x;
        to=y;
        v=z;
    }
}e[10001];

int first[10001];
int tot;
int dis[100001];
int q[100001];
int v[100001];
void add_edge(int x, int y,int z) {
    e[++tot] = edge(first[x], y,z);
    first[x] = tot;
}
int n;
int N=31;

int inc(int x) {
    x = x + 1;
    x = x % N;
    return x;
}

int dec(int x) {
    x = x - 1 + N;
    x = x % N;
    return x;
}

void spfa(int S) {
    int p, x, y, l, r;
    for (x = 1; x <= n; ++x)
        dis[x] = 0x7ffff;
    q[0] = S, dis[S] = 0, v[S] = 1;
    for (l = r = 0; l != (r + 1) % N; ) {
        p = q[l];
        cout<<"从第"<<p<<"号边开始遍历"<<endl; 
        l=inc(l);
        for (x = first[p]; x; x = e[x].next)
        {
            cout<<"这时是第"<<x<<"号边"<<endl; 
            if (dis[p] + e[x].v < dis[(y = e[x].to)]) {
                cout<<"更新"<<" "<<""<<dis[y]; 
                dis[y] = dis[p] + e[x].v; 
                cout<<"更新为"<<dis[y]<<endl; 
                if (!v[y]) {
                    v[y] = 1;
                    if (dis[y] < dis[q[l]]) 
                    {q[(l=dec(l))] = y;
                    cout<<"从队首插入"<<y<<endl; 
                    cout<<"这时l为"<<l<<"r不变"<<endl; 
                    } 
                    else 
                    {q[(r=inc(r))] = y;
                    cout<<"从队尾插入"<<y<<endl; 
                    cout<<"这时l不变r变为"<<r<<endl; }
                    cout<<"更新后的队列为"<<endl; 
                    for(int i=0;i<=n;i++)
                    {
                    cout<<q[i]<<" "; 
                    } cout<<endl;
                    cout<<"入队情况为"<<endl;
                    for(int i=1;i<=n;i++)
                    cout<<""<<i<<"号元素"<<v[i]<<" ";
                    cout<<endl;
                }
            }
        }
        v[p] = 0;
        cout<<"此时最短路径被更新为"<<endl; 
        for(int i=0;i<=n;i++)
        {
            cout<<dis[i]<<" ";
        }
        cout<<endl;
    }
}


int main()
{
    int m,S;
    cin>>n>>m>>S;
    int x,y,z;
    for(int i=1;i<=m;i++)
    {
        cin>>x>>y>>z;
        add_edge(x,y,z);
    }
    
    spfa(S);
    cout<<"最终最短路径"<<endl;
    for(int i=1;i<=n;i++)
    {
        cout<<dis[i]<<" ";
     } 
    
    cout<<"一共有"<<tot<<"个节点,分别是"<<endl;
    for(int i=1;i<=tot;i++)
    {
        cout<<"与它同起点的上一对点为"<<e[i].next<<""<<" "<<"它指向"<<e[i].to<<"这个点"<<endl;
    }
    cout<<"下面输出First数组"<<endl;
        for(int i=1;i<=tot;i++)
    {
        cout<<first[i]<<" ";
    }

}

这是举例用的样例:

4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
到这里就结束啦!希望可以看懂!
蒟蒻的第二篇博客(再放个烟花吧!)

Guess you like

Origin www.cnblogs.com/Daz-Os0619/p/11388157.html