spfa及slf优化

spfa,不用多讲了吧,相当实用的BF队列优化算法,裸代码如下

program spfa;
var    pre,last,other,long:array[0..1000001] of longint;
    d,short:array[0..1000001] of longint;
    ok:array[0..1000001] of boolean;
    head,tail,m,n,i,j,k,tot,x,y,z:longint;
procedure add(x,y,z:longint);
begin
    inc(tot);
    pre[tot]:=last[x];
    last[x]:=tot;
    other[tot]:=y;
    long[tot]:=z;
end;
begin
    readln(n,m);
    for i:=1 to m do
    begin
        readln(x,y,z);
        add(x,y,z);
        add(y,x,z);
    end;
    fillchar(ok,sizeof(ok),true);
    fillchar(short,sizeof(short),127);
    head:=0;
    tail:=1;
    d[1]:=1;
    short[1]:=0;
    while head<tail do
    begin
        inc(head);
        ok[d[head]]:=true;
        i:=last[d[head]];
        while i<>0 do
        begin
            if short[other[i]]>short[d[head]]+long[i] then
            begin
                short[other[i]]:=short[d[head]]+long[i];
                if ok[other[i]] then
                begin
                    ok[other[i]]:=false;
                    inc(tail);
                    d[tail]:=other[i];
                end;
            end;
            i:=pre[i];
        end;
    end;
    for i:=1 to n do writeln(short[i]);
end.

用这个程序轻松求出从标号1到各点的距离。

如果起点不是1,又要怎么做呢?

1)暴力法

  很容易想到,数组存下所有边的起点,中点及权值,再将所有点权加上(n-x) mod n + 1,其中n表示点数,x表示所求起点。

  正确性显然,就不多证明了。

2)更改spfa主要部分如下:

  ①将队首元素更改为所求节点

  ②由该点向外拓展至各边并比较,记录

  由此,我们将一个spfa变成了可以求从任意起点到其他点最短路的算法

  代码就不贴了,大家可以自己写一下,利用上面的可以直接改变量,或者把主要部分放进procedure里

3)slf优化

  详见百度百科,大家可以自行查找,通过将部分点放于队首减少更新的算法优化,代码贴c++了,DeAR神犇手打

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

//variable//
int last[100000],prel[100000],dest[100000],cost[100000],tot=1;
int vis[100000],q[1000000],dis[100000];

//function prototype//
void addline(int,int,int);
void spfa_slf(int);

//solve//
int main(){
    int n,m,u,v,w;
    scanf("%d%d",&n,&m);
    for (int i=0;i<m;++i){
        scanf("%d%d%d",&u,&v,&w);
        addline(u,v,w);
    }
    spfa_slf(1);
    printf("%d\n",dis[n]);
    system("pause");
    return 0;
}

void addline(int u,int v,int w){
    dest[++tot]=v;
    prel[tot]=last[u];
    last[u]=tot;
    cost[tot]=w;
}

void spfa_slf(int x){
    memset(dis,0x7f,sizeof dis);
    memset(vis,0,sizeof vis);
    int he=500000,ta=500000;
    dis[x]=0;vis[x]=1;q[he]=x;
    while (he<=ta){
        int u=q[he++];
        vis[u]=0;
        for (int k=last[u];k;k=prel[k]){
            if (dis[dest[k]]>dis[u]+cost[k]){
                dis[dest[k]]=dis[u]+cost[k];
                if (!vis[dest[k]]){
                    vis[dest[k]]=1;
                    if (dis[dest[k]]<dis[u]){
                        q[--he]=dest[k];
                    }else{
                        q[++ta]=dest[k];
                    }
                }
            }
        }
    }
}

 

posted @ 2015-09-09 21:45  ROLL-THE-FIRST  阅读(674)  评论(0编辑  收藏  举报