2020年春招暂告一段落了。总结一下今年春招的编程题,今年好多厂的笔试题都出现了关于图的最短路径的编程题。
先还原一下题目:
假设某地区有五个城市,为了方便玩家在不同的城市活动,在每个城市都有传送点可以到达另外某个城市,这些城市之间满足以下条件:
- 任意两个城市之间不一定可以直接传送
- 可直接传送的任意两个城市传送时间会受距离的影响,距离越远传送时间越长
- 传送是单向的,即如果V1可以直接传送到V2,那么V2不可以直接传送到V1
请设计一个程序,能够计算出V1到其他各个城市的最短时间。
这个题目很明显,就是求图中最短路径,今天我们就讲讲求图中最短路径的算法–Dijkstra(迪杰斯特拉)算法。
迪杰斯特拉算法采用的是贪心策略。具体的思想如下:
- 首先设置一个距离表dis,用来记录源点到各个顶点的距离。
- 先从未访问顶点集合U中找到距离源点路径最短的顶点,放入已访问顶点集合V。
- 当已访问顶点集合V更新之后,更新距离表dist。
- 重复这个过程,直到已访问顶点集合包括了图中所有V1可以到达的顶点。
举个例子,如下图所示的一个有向图中,设V1为起始点(源点)。
初始化的距离表如下所示,此时已访问顶点集合还是空的。
当把V1顶点放入已访问顶点集合中,此时V3,V5,V6都是V1的邻接顶点,而V2和V4并没有与V1邻接,所以与V1的距离置为∞。
在与V1的邻接的V3,V5,V6顶点中,V3是距离V1最近的顶点,所以,把V3放入已访问顶点,并更新距离表。
更新后的距离表可以看到,V3的访问标志位被置为True,说明V3放入已访问顶点集合中了;V4与V1的距离变成了60,这是为什么呢?因为当V3放入顶点集合中,V1可以先访问V3,再访问V4。简单的说就是V1通过V3可以走到V4这个地方了,所以距离为10+50=60。
这时候再在V2,V4,V5,V6中选择距离V1最近的,V5,就是你了!把V5放入已访问顶点集合中去,此时的距离表变为:
咦~V4和V6到V1的距离咋变了呢?
这是因为由于V5顶点加入到已访问顶点集合中去,V1到V4的路径就变成两条V1->V3->V4,V1->V5->V4,这两条路我们肯定要选择最短的啊,经过比较发现V1->V5->V4这条路径最短,所以V1到V4的距离更新为30+20=60。同理,V1到V6的两条路径V1->V6,V1->V5->V6,我们比较发现V1->V5->V6会更短,所以V1到V6的距离更新为30+60=90。
这时候再在V2,V4,V6中选择距离V1最近的,去吧,V4!把V4放入已访问顶点集合中去,此时的距离表变为:
由于V4加入到已访问顶点集合中去,V1到V6的路径就更新为V1->V5->V4->V6,距离更新为60。
然后再把V6加入到已访问顶点集合中去
对于V2,它本来就是个不合群的顶点,V2只有一条往V3去的路,所以V1是不能够到达V2的。
以下是python代码的实现