2016.7.20晚 听课收获

今天,跟着昨天晚上的图的相关知识,他又讲了图的遍历,也就是求最短路径。

求最短路径先讲了floyd算法。最大的收获就是明白了为什么中转点k要放在外里面。

可以用反证法。意思就是:如果当前中转点放在外面或i,j循环的中间时,就会使得如果当前第k个点都大于i,j的话,第i个点到第k个点或第j个点到k点就会还没算好,如果还没算好再去更新i到j的最短路径就没有意义了,也就会使得答案错误。而放在里面则不会,仔细想想就就能明白。

其次我们也可以想到由一条i到j的最短距离,在Floyd就是由i~k,再从k~j的两个状态的值得来的。所以我们每次求解f[i,k]的时候,因为k在外面,所以每次都可以吧f[i,k]变成一个f[i,k']加f[k',k]的子问题,依次求出子问题的值,就可得知在算i~j的距离时,f[i,k]和f[k,j]的值必定是已算过的(但有可能i走不到k或者k走不到j,但这个值一定是被“更新”过的。)


其次是Spfa算法。

其实spfa算法是bellman ford算法的优化,也就是其中心思想就是bellman ford。因为易证在求到第i个点的时候不需要状态t(t表示当前走了多少个点)。易得出如果设a[i,j]表示第i个点所连向的第j个点,b[i,j]表示距离,则f[a[i,j]]就等于min{f[i]+b[i,j]}

其实对于spfa算法最大的收获就是储存节点的方式:


以前做题时经常用的是最容易想到的邻接表储存。但,如果有10000个点,只有100000(或再多一些)条边,则如果数据极端一点,1个点就连向了剩下所有的点,则需把邻接表开到10000*10000,当题目空间有限制的时候明显是行不通的。


因为边数有限,所以我们可以采用另一种储存边的方式:

假设当前有一条x到y的边,距离为z。

那么,我们当找到这么一条边的时候,就需把当前边的总数+1.并记录。

可以用tov[tot]表示以第x个点所去向的点,len[tot]表示去向这个点的距离。

last[x]表示以x为节点,所连向的最后一条边的编号。next[tot]表示当前第tot条边所记录的上一条边。

可得知记录的总过程为:

procedure insert(x,y,z:longint)

{

inc(tot);

tov[tot]=y;

len[tot]:=z;

next[tot]:=last[x];

last[x]:=tot;

}

记录好之后,我们可以每次把一个t赋值为last[x](x为当前往其他点拓展的点)然后判断tov[t]的最优(spfa里面的更新最优值)最后把t赋值为next[t],知道next[t]为0时就不继续拓展下去。


最后,我们分析一下时间复杂度和时空复杂度。

时间复杂度对于floyd来说,毋庸置疑O(n³)

而对于spfa,段凡丁给出的是O(km)(m为边数,k是常数,在随机情况一般小于等于2)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值