2016.7.20晚 听课收获
2016-07-21 22:54
218 查看
今天,跟着昨天晚上的图的相关知识,他又讲了图的遍历,也就是求最短路径。
求最短路径先讲了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)
求最短路径先讲了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)
相关文章推荐
- Android中.this的意思
- 【Get深一度】dB、dBm、dBW和W换分别代表的含义及换算关系
- Retrofit 2.0 超能实践(四),完成大文件断点下载
- ubuntu 14.04更新源
- Retrofit 2.0 超能实践(四),完成大文件断点下载
- L1-019. 谁先倒-PAT团体程序设计天梯赛GPLT
- static关键字
- UVA 11988 链表
- 《代码大全》中推荐的一些程序员和软件工程师需要读的书籍
- 怎样提高网站用户体验
- 怎样提高网站用户体验
- workday3~4
- iOS开发小技巧--即时通讯项目:使用富文本在UILabel中显示图片和文字;使用富文本占位显示图片
- 前端设计模式责任链模式
- Objective-C & Sprite Kit太空历险记 : 2. 初级训练营——Objective-C基础(上)
- Nagios-安装与配置
- 广播
- L1-023. 输出GPLT-PAT团体程序设计天梯赛GPLT
- java的++和--操作符
- 【ReactNative】真机上无法调试 could not connect to development server