我的OI心得(四)之 图论(三)

单源最短路径

重点课题!

单源最短路径(SSSP)是这样一个问题:在一张图中,有一个源点S,点与点之间有边,边上有权值,表示从边的这头走到边的那头要付出的代价(距离)。求点S到其余所有点的最小距离。

书上讲了Dijkstra。朴素Dijkstra呢,NOIP一般就是小数据用用,O(n2)敷衍了事(如果你觉得用着顺的话);对付大数据也不是不行,但是得加个堆(相关章节自行查阅),用于维护和查询当前的距离最小的点再加上邻接表或边集数组,复杂度降为O(nlgn+e),不过编程复杂度较高,不赞成使用。但是Dijkstra的思路还是要搞懂的——就是说我每次都选“还没确定的”到源点距离最小的点i,他当前的到S的距离d[i]一定可以确定是iS的最短距离:没有比他更小的没更新过他的点了。把这个点选出来(可以用堆)后,用他更新与他直接相连的若干点,跟他们说:哥们,走我这试试看,能不能更近点。然后西去修成正果——i也变成了“已确定的点”。做n-1个点后(d[s]=0),算法结束。

然而我要说的是——我们可以用宽搜做!状态就是当前点的编号!加上上面的数组d,这个叫SPFA的算法效果非常好!注意在Dijkstra中有个Relax操作:设i->j的边权为c[i,j],则我们可以做如下操作:if d[j]>d[i]+c[i,j] then d[j]=d[i]+c[i,j];。这步操作很关键。如果上述语句成功执行,那么无疑d[j]将变小,那么所有j连出去的点的d值也有可能变小,应此我们应当挨个访问一下。不急,我们学学人家宽搜,用个队列,把j扔队尾去(如果j不在队列的话)

流程如下:

procedure SPFA(s:integer);

var

n,v,u,t1,t2:integer;

d:array[1..1000]of integer;

c:array[1..1000,1..1000]of integer;

queue:array[1..1000]of intger;

begin

   t1=1;t2=1;q[1]=s;

   repeat

         u=q[t1];inc(t1);flag[u]=false;

for v:=1 to n do

if (c[u,v]>0) and (d[v]>d[u]+c[u,v]) then

begin

      d[v]:=d[u]+c[u,v];

      if not flag[v] then

      begin

           inc(t2);q[t2]:=v;flag[v]:=true;

      end;

end;

           until t1=t2;

end;

事实上,SPFANOIP中最常用的单源最短路径算法——也就是宽搜+判重(d数组和flag数组)。

SPFA更深入的了解见姜碧野童鞋的2009国家队论文之《SPFA算法的优化及应用》。国家队论文是个好东西!!

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值