最短路算法汇总

2014-11-23 18:02:01 · 作者: · 浏览: 16

校赛完了,这次校赛,做的很差,一个算法题没有,2个水题,1个贪心,概率DP,DP,数论题。DP还没开始研究,数论根本不会,数学太差了,省赛时卡数论,校赛依然卡数论,我擦,还是得继续学习啊!

一把锈迹斑斑的剑,只有不断的磨砺,才能展露锋芒!

以下为最短路总结:


最短路问题可分为:


一、单源最短路径算法,解决方案:Bellman-Ford算法,Dijkstra算法,SPFA

二、每对顶点间的最短路径算法:Floyd;


(1).Dijkstra算法:


(经典的算法,可以说是最短路问题的首选事例算法,但是不能处理带负权的边,因为该算法要遍历的点过多,效率低下,用时长,仅限于小数据,不常用)

基本思想:
Dijkstra算法,本质上是利用贪心思想来不停的来进行贪心选择,查找最优解,开辟一个s[],用来存放这些点,

dis[]用来存放所能经过的每个点的最短距离,并进行dis[]的更新操作。



模版如下:
   int m,n,map[max][max],dis[max],s[max];
//int prev[max];//当前点的上一个节点
   
    void Dijkstra(int v0)
  {
    for(int i = 0;i
  
   
(2).Bellman-Ford

(用来判断是否有回环,可处理带负权边 时间复杂度O(V*E).)

基本思想:(DP思想,查找最优解,并不断的进行松弛操作,但是算法浪费了许多时间做冗杂的松弛操作,效率降低)
void add()
{
    scanf("%d%d%d",&u,&v,&w);
    edge[l].u = u; edge[l].v = v; edge[l++].w = w;
    edge[l].u = v; edge[l].v = u; edge[l++].w = w;
}


int Bellman(int cnt)
{
    int i,j,flag;
    for(i = 1;i <= N - 1;i++)
    {
        flag = 0;
        for(j = 0;j <= count - 1;j++)
          {
              if(dis[edge[j].u]> dis[edge[j].v] + edge[j].w)
                {    //松弛计算
                dis[edge[j].u] = dis[edge[j].v] + edge[j].w;//更新dis[]数组,使其存储 源点->当前点的最短距离
                flag = 1;
                }
          }
        if(flag==0)//如果查找完,或者有些点达不到,跳出
            break;
    }
    for(i = 0;i < count;i++)//判断是否有负环路
        {
            if(dis[edge[i].u] > dis[edge[i].v] + edge[i].w)//更新完dis[]后,如果还存在 该成立条件,则存在负环路
            return 1;                                     
        }                                              //  如1->2 权值2
    return 0;                                         //     2->3 权值5
                                                      //     3->1 权值-8
                                                    //       1->2->3->1 一次循环为-1 二次-2  三次....
}

(2)FLOYD
这个实在没什么好说的,做题目时,只要确定的 时间不超,就可以用,前提是记下,时间复杂度O(n*n*n).


 void init() 
{  
         for(i=0;i
    
     map[i][k] + map[k][j] )
                   {
                    map[i][j]=map[i][k]+map[k][j];
                   }
                 }
             }
      }
}
    

(4)SPFA

书上说是在bellman-ford的基础上,添加一个队列操作,减少了其不必要的松弛操作。

我个人认为是在BFS搜索的基础上加了一步所谓的松弛操作,至于为什么叫松弛,不懂。

但是SPFA优化的很棒,以后最短路问题,尽量用它


void SPFA(int s,int e)   S点 到e点
{
    int l,r,i;
    l=r=0;
    memset(vt,0,sizeof(vt));
    for(i=0;i
    
     dis[p] + map[p][i])
            {
                dis[i] = dis[p] + map[p][i];
                if(!vt[i])
                {
                    q[r++] = i;
                    vt[i] = 1;
                 }
            }
        }
        vt[p] = 0;
    }
    if(dis[e]!= inf)
    printf("%d\n",dis[e]);
    else
    printf("-1\n");
}