简单单源最短路径笔记QwQ

推荐阅读:

国家集训队论文2006 《最短路算法及其应用》 By 广东北江中学 余远铭 

国家集训队论文2009 《迭代求解的神器——spfa算法的优化和应用》By 中山纪念中学 姜碧野

以及   《算法导论》

 

注意:以下模板题目是:P3371 luogu

 luoGu的模板题比较坑,因为相邻的两点间的边可能有3条以上,所以对于floyed和dijkstra从i到j的边如果有多条要取最短的那条,

但是对于spfa和bellman-ford就不用啦 2333

Floyed ——O(n^3)

通过一个图的权值矩阵求出它的每两点间的最短路径矩阵。——from 知乎 

关键是枚举中间点

 

伪代码:

for k:= 1 to n do 
  for i:= 1 to n do 
     for j:= 1 to n do 
        f[i,j]:=min(f[i,j],f[i,k]+f[k,j]);

 

巧妙的Floyd优化,删点那一题目——小X的最短路,从删光点开始往前推,每次增加一点,不能照搬Floyd,要分别以他为起点,终点,中转点来一次Floyd,复杂度大概O(N^3)

还能用来判断点的连通性。

 

Dijkstra  ——O(n^2)

不能处理负边权!                                         

 图片来自维基百科   图片来自维基百科

主要思想:

初始化数组为maxlongint div 3;   c[i]表示起点到i点的最短距离

从起点开始找,直到找了n-1个点

每次找离当前点最近的蓝点【包括自己】,把它变白,以此为中转点更新与之相连的蓝点到起点的距离。

使它到起点的距离不再是maxlongint div 3或者其他,所以下一个找的蓝点说不定就是它,如图点7

图片来自《算法导论》

模板:

//纯dijkstra ,    Score: 70 MLE
program shortest;
var
  n,i,a,b,m,j,s,e,min,k,tmp:longint;
  x,y:array[1..500000] of longint;
  che:array[1..1000] of boolean;
  c:array[1..1000] of longint;
  f:array[1..1000,1..1000] of longint;
begin
  readln(n,m,s);
  fillchar(f,sizeof(f),$5f);

  for i:= 1 to m do
  begin
    readln(x[i],y[i],tmp);//x表示边的左端点,y表示边的右端点
    if (f[x[i],y[i]]>0) and (f[x[i],y[i]]>tmp) then f[x[i],y[i]]:=tmp;
  end;
  for i:= 1 to n do c[i]:=f[s,i];
  c[s]:=0;

  for i:= 1 to n-1 do
    begin
      min:=maxlongint;  k:=0;
      for j:= 1 to n do
        if che[j]=false then
          if c[j]<min then
            begin
              min:=c[j];
              k:=j;
            end;
      if k=0 then break;
      che[k]:=true;
      for j:= 1 to n do
        if c[j]>f[k,j]+c[k] then c[j]:=f[k,j]+c[k];//如果要记录前驱要在这里的relax添加pre的记录
    end;

  for i:= 1 to n do if c[i]<>1600085855 then write(c[i],' ') else write('2147483647 ')

end.

 

Bellman-Ford——O(NE)

无法处理负权回环

 思想

每次都对M条边做一遍relax操作,必然会有至少一个蓝点turn white.

假设最坏情况(relax),每次只有一个蓝点变白,那么我们至少要n次*m次的relax操作!

 模板

//Score: 70   , DATE8-10: TLE
program shortest;
var
  n,i,a,b,m,j,s,e:longint;
  x,y:array[1..500000] of longint;
  w:array[1..500000] of longint;
  c:array[1..10000] of longint;

procedure printf();
begin
  for i:= 1 to n do
   if c[i]<>2139062143 then write(c[i],' ')
   else write('2147483647 ');
end;

procedure init();//初始化过程
begin
  fillchar(c,sizeof(c),$7f);                 //这样会得到一个接近maxlongint的数——2147483647
   c[s]:=0;
end;
function bellman_ford:boolean;
begin
  init;
  for i:= 1 to n do
    for j:= 1 to m do
       if c[y[j]]>c[x[j]]+w[j] then c[y[j]]:=c[x[j]]+w[j]; //relax,注意有无向

  {for j:= 1 to m do                          //判断负权回路
  if (c[y[j]]>c[x[j]]+w[j]) then exit(false);}//根据路径松弛性质,最短路径中的边的最短路径估计值在达到下限后不再会改变,除非出现负权回路
  exit(true);                                 //虽然该题不会有负权回路
end;

begin
  readln(n,m,s);
  for i:= 1 to m do
    readln(x[i],y[i],w[i]);//x表示边的左端点,y表示边的右端点

  if bellman_ford then printf
  else writeln('Impossible');               
end.

 

 SPFA:

 

 

 

 

 

 

 

 其他

以下内容来自《算法导论》第三版

relax操作

对最短路径的估计值的收紧【更新】并更新前驱

《算法导论》第三版

《迭代求解的神器——spfa算法的优化和应用》

 

相关性质

注意:为连接u和v的边的权值,即dis[v],表示从起点到v点的最短路径的估计值,表示s到v的最短路径长度,就是的下界

 P.S. 感觉似乎没有必要证明,想想就知道。。

 

(1)反证法证明最短路径的子路径也是最短路径

定理1 (最优子结构给定有向加权图G=(V,E),设P=<v1, v2,, vk>为从结点v1到结点vk的一条最短路径,对任意i,ji<=j<=k,设Pij=< vi, vi+1,, vj>为从vivjP的子路径,Pij是从vivj的一条最短路径。

证明:我们把路径P分解为<v1,v2,,vi,vi+1,vj,vk>。则w(P)=w(P1i)+w(Pij)+w(Pjk)。现在假设从vivj存在一路径Pij,且w(Pij)<w(Pij),则将P中的路径Pij=(vi,vi+1,vj)替换成Pij,依然是从v1vk的一条路径,且其权值 w(P1i)+w(Pij)+w(Pjk)小于w(P),这与前提P是从v1vk的最短路径矛盾。(证毕)

(2)三角不等式性质

(3)上界性质:对于

(4)非路径性质:没有路径(注意不是边)相连的点到起点的最短路径为∞

(5)收敛性质:当达到下界时,任何relax操作都不会让它再发生变化

(6)路径松弛性质:对最短路径中的第k条边保证

转载于:https://www.cnblogs.com/bobble/p/6388405.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值