最短路模板-folyd bellman Dijkastra+路径还原+SPFA

来源:互联网 发布:ps4游戏卖给淘宝店家 编辑:程序博客网 时间:2024/05/26 07:27
以下所有算法都不能解决负圈的最短路,因为有负圈的路不存在最短路,但是只有Dijkstra不能处理带有负边的最短路。

一、先是最好理解的folyd算法
注意k在最外层,为什么k一定要在最外层?
假设k在最内层,那么从 i 到 j 的点 只确定一次最短路(k从1到n),过早地确定了 i 到 j的最短路,但如果把k放在外曾,k从1-n过程中,i 到 j 确定了 n次
贴一个讲解这个的博客 http://www.cnblogs.com/twjcnblog/archive/2011/09/07/2170306.html

1、解决任意两点的最短路情况
int n;int map[110][100];void floyd ()//以每个点为起点到每个点的最短路,(map表示边的权值,不存在边设为无穷大){    for(int k=1;k<=n;++k)//k一定在最外层    {        for(int i=1;i<=n;++i)            for(int j=1;j<=n;++j)                map[i][j]=min(map[i][j],map[i][k]+map[k][j]);    }}


二、bellman- ford算法

1、解决单源最短路
以边的顺序计算最短路,最多进行V-1次
struct edge{    int from,to,cost;}es[maxn];int V,E;int d[maxn];//d【i】表示从s到i的最短路,初始值除d【s】外都为INFvoid bellman_ford(int s)//从s到每个点的最短路{    for(int i=0;i<V;++i)        d[i]=INF;    d[s]=0;    while(1)    {        bool update = false;//判断是否全部更新完了        for(int i=0;i<E;++i)        {            edge e = es[i];//按顺序取出每一条边            if(d[e.from]!=INF && d[e.from]+e.cost < d[e.to])            {                d[e.to] = d[e.from] + e.cost;                update = true;//这一轮取所有边后有更新            }        }        if(!update) break;    }}

2、利用上述性质可以判断是否有负圈,如果有负圈,会不断进行更新,那么将会超出v-1次
//bellman-ford判断存不存在负圈;bool find_negative_loop(){    memset(d,0,sizeof(d));    for(int i=1;i<V;++i)        for(int j=0;j<E;++j)        {            edge e=es[j];            if(d[e.to]>d[e.from]+e.cost)            {                d[e.to] = d[e.from] +e.cost;                if(i== V-1) return true;//第v-1次仍然进行了说明有负圈            }        }        return false;}

三、Dijkastra算法
Dijkastra是上一个算法的优化,将已经确定最短路的点去掉,只考虑没确定过最短路的点.这个不好理解,为什么是正确的就不证明了,贴一个讲的很好的博客 http://blog.csdn.net/mengxiang000000/article/details/50421243
我认为大概就是分为两步,第一步从尚未使用过的点中选取一个距离起点最近的点,第二步,把选取的点与之能到的点更新

1、单源最短路
//Dijkastra算法bool used[maxn];int d[maxn];void dijkastra( int s){    memset(d,INF,sizeof(d));    memset(used,0,sizeof(used));    d[s]=0;    while(1)    {        int v=-1;//相当于bellman算法中的update,又有所不同        //第一步从尚未使用过的点中选取一个距离起点最近的点(第一次取得是起点s)        for(int u=0;u<V;++u)        {            if(!used[u] && (v== -1 || d[u]<d[v])) v=u;        }        if(v==-1) break;//所有点都确定最小值了,无点可取        //第二步,把选取的点与之能到的点更新        else        {            used[v]= true;//把这个点标记            for(int u=0;u<V;++u)            {                d[u]=min(d[u],d[v]+map[v][u]);            }        }    }}

2、还原路径
因为从i - j 的最短路 要么是直接通向,要么是一点点更新来的, 所以每次只需要记录当前点的最短是哪个点更新来的就可以。然后利用递归输出就可以,这里直接摘抄书上的代码,用的是dijkastra 算法 c++的vector实现的。

//Dijkastra算法还原路径bool used[maxn];int d[maxn];int prex[maxn];void dijkastra( int s){    memset(d,INF,sizeof(d));    memset(used,0,sizeof(used));    memset(prev,-1,sizeof(prev));    d[s]=0;    while(1)    {        int v=-1;//相当于bellman算法中的update,又有所不同        //第一步从尚未使用过的点中选取一个距离起点最近的点(第一次取得是起点s)        for(int u=0;u<V;++u)        {            if(!used[u] && (v== -1 || d[u]<d[v])) v=u;        }        if(v==-1) break;//所有点都确定最小值了,无点可取        //第二步,把选取的点与之能到的点更新        else        {            used[v]= true;//把这个点标记            for(int u=0;u<V;++u)            {                if(d[u]>d[v]+map[v][u])                {                    d[u]=d[v]+map[v][u];                    prev[u]=v;                }            }        }    }}void get_path(int t){    vector<int> path;    while(t!=-1)    {        path.push_back(t);        t=prev[t];    }        reverse(path.begin(),path.end());        return path;}



四、SPFA
SPFA(Shortest Path Faster Algorithm)(队列优化)算法是求单源最短路径的一种算法,它还有一个重要的功能是判负环(在差分约束系统中会得以体现),在Bellman-ford算法的基础上加上一个队列优化,减少了冗余的松弛操作,是一种高效的最短路算法。

int map[maxn][maxn];int dis[maxn],visit[maxn];void init()//初始化map{    int i,j;    for(i=0;i<maxn;++i)        for(j=0;j<maxn;++j)        {            if(i==j)                map[i][j]=0;            map[i][j]=map[j][i]=INF;        }}void spfa(int start){    queue<int> q;    int i,now;    memset(dis,INF,sizeof(dis));    memset(visit,0,sizeof(visit));    dis[start]=0;    q.push(start);    visit[start]=1;    while(!q.empty())    {        now=q.front();        q.pop();        visit[now]=0;        for(i=1;i<maxn;++i)        {            if(dis[i]>dis[now]+map[now][i])            {                dis[i]=dis[now]+map[now][i];                if(visit[i]==0)                {                    q.push(i);                    visit[i]=1;                }            }        }    }}



1 0
原创粉丝点击