求单源最短路径的经典
2. 从V-S中选取这样一个顶点w: 满足经过S集合中任意顶点 v到w 的路径最短, 即
满足( 源到v的路径 + v到w的路径) 最小的那个w. 其中v 属于S, w属于S-V。将w 加入S, 并从V-S中移除w.
3. 如此反复,直到V-S变空集为止。
归纳基点:
比如开始 S中只有原点s, 那我们从V-S中选取离s最近的点w, 则s直接到w的路径一定最短。因为如果存在另一个点w2, 使得
s->w2->w 的路径比s
直接到w短,那么s->w2 一定 小于s->w, 那么
w就不是离s最近的点,与我们选取的w离s最近这个先前条件矛盾。所以在最开始,选出来的那个点 w
一定确定了最短路径,即s->w 的边长。 w已经确定,将w加入S.
2. 此时S中有 v1,v2....vk 顶点,V-S中剩下 w1,w2.....Wn-k
顶点。我们此时当然选择离S集合最近的点w.
w必然满足 D[w]= Min(D[v]+D[v to
w]) 其中 D[x]
表示从原点到x的最短路径长。
这个w 此时一定取得了最短路径D[w], 因为如果有其他的路径,假设是
S集合某路径->Wi->w, 那么就应当去选取Wi 做为该点而不是w.
因为 S集合某路径长D[v] + D[v to Wi] < D[v]+D[v to w] 与
w满足的公式矛盾。
因此w必然是最小的。将w加入 S集合。
3. 实现框架+核心代码:
采用邻接表存储图
1
4 public class Edge {
5 public Vertex dest;//目标顶点
6 public double cost;//代价
7
8 public Edge(Vertex d,double c){
9 dest=d;
10 cost=c;
11 }
12 }
13
顶点类:
1 public class Vertex implements
Comparable{
2 public String name;//顶点名
3 public List adj;//邻接表
4 public double dist;// 从原点到该点的最短路径长
5 public Vertex prev;//最短路径前一个节点
6 public int scratch;//算法需要
7 public boolean visited;
8 public Vertex(String nm){
9 name=nm;
10 adj=new ArrayList();
11 reset();
12 }
13 public void reset(){
14 visited=false;
15 dist=Graph.INFINITY;
16 prev=null;
17 scratch=0;
18 }
19 @Override
20 public int compareTo(Vertex o) {
21 double c=o.dist;
22 return distc?1:0;
23 }
24 }
25
1
9 public void dijkstraSlow(String startName){
10 PriorityQueue pq=new
PriorityQueue();
11 Vertex start=vertexMap.get(startName);
12 if(start==null)
13 throw new IllegalArgumentException("Hey fk,start vertex is
illegal!");
14 clearAll();
15 //pq.add(start);
16 start.dist=0;
17 //构造V-S集合,将顶点全部装入优先级队列(V-S集合).
18 //优先级队列的队首元素即离原点最近的,因为Vertex对象的比较器是
19 //根据Vertex对象到原点的距离来比较的。
20 //其实这里可以进一步优化的,由于开始选中加入S的必定是原点,
21 //且只有刚加入S的顶点的邻接顶点才有可能是新的加入S的顶点,
22 //所以开始只要把原点放入vertexMap即可,第一次将原点加入S,
23 //然后更新其邻接点到原点的距离.从中选出最小的来加入S。
24 //这里为了保持算法清晰,没有进行优化.
25 for(Vertex v:vertexMap.values())
26 pq.add(v);
27
28
29 int seenNum=0;
30 while(!pq.isEmpty()&&seenNum
31
32 Vertex v=pq.remove();//第一次取的是原点,其余情况自然是到原点最近的点.
33
34 if(v.scratch!=0)//如果v已经加入了S,则跳过
35