2018.3.26 Practice makes perfect
写给自己:
Dijkstra算法是经典的最短路径算法,和Floyd算法相比,它在智能求得某特定结点到其他所有结点的最短路径,即单源最短路径算法。
这个算法设计精巧,一开始理解起来比较费劲,所以首先建立要一个感性的认识,我们想象自己是一个随遇而安,不是那么的有强迫症思想的人,我们想要知道结点1到结点6的最短路径,那么我们先会找到结点1,看看从结点1出发能到达哪几个结点,把这几个结点记录下来。
i | 1 | 2 | 3 | 4 | 5 | 6 |
最短到达 | 0 | -1 | -1 | -1 | -1 | -1 |
这里会记录结点2 , 结点3 ,结点4 , 那么要选择哪一条呢,我们先不考虑未来的事情,我们就先随遇而安,活在当下,那我们肯定要选择最短的路径1->2 长度为2 ,但是我们知道如果只这样做很可能会误入歧途,所以我们也会记录下我们当初能够选择的到各结点的长度。
i | 1 | 2 | 3 | 4 | 5 | 6 |
最短到达 | 0 | 2 | 3 | 4 | -1 | -1 |
我们当前还认为是走结点2是最好的选择哦,所以继续由我们所认为的最好的结点开始找从它可以走到的位置,
发现结点2可以走到结点3,但是呢,2->3的路径为2,再加上1->2的路径2,一共是4,与之前已经记录的3相比大了,所以我们开始了反思,是不是一开始选择走结点2是有问题的,那我们不改变从1->3的距离3,那么现在我们要从哪里搜索了呢,因为结点2已经搜索过了,将其排除在外,剩下的结点3、4、5、6里我们肯定选最短的路径咯,就算它最后不是最短路径的组成部分,那我们也选择它,那么现在从结点3开始寻找。因为结点5,结点6原本都是不能到达的,现在可以到达了,不管是不是最短路径,先记上再说。
i | 1 | 2 | 3 | 4 | 5 | 6 |
最短到达 | 0 | 2 | 3 | 4 | 8 | 9 |
既然结点1,2,3都已经访问过了,我们依旧原来的策略,在剩下的没有访问过的结点中,挑选最短的,这里就算结点4,由结点4走到5,一共只需要6,刷新了之前的记录。
i | 1 | 2 | 3 | 4 | 5 | 6 |
最短到达 | 0 | 2 | 3 | 4 | 6 | 9 |
然后选择从结点5出发,到结点6,一共是8,再一次刷新了之前的记录9。
i | 1 | 2 | 3 | 4 | 5 | 6 |
最短到达 | 0 | 2 | 3 | 4 | 6 | 8 |
这样以后,从1->6的最短路径是8。
有了这个直观的理解,有助于我们对于代码的理解,虽然我对于其证明过程目前还有些困惑,但是能有逻辑的记住代码的写法也是极好的。
#include <stdio.h>
#include <vector>
using namespace std ;
//表示边长的结构体
struct E
{
int next ;
int c ;
};
//邻接链表,储存以每一个点为起点的边,如果是无向图,那么每一条边的信息添加在两个顶点上
vector<E> edge[101] ;
bool mark[101] ;
int Dis[101];
int main()
{
int n , m ;
//以下是输入格式,不用太在意
while(scanf("%d%d",&n,&m) != EOF)
{
if(n == 0 && m == 0) break ;
for(int i = 0 ;i <= n ; i++) edge[i].clear();
while(m--)
{
int a , b, c ;
scanf("%d%d%d",&a,&b,&c);
E temp ;
temp.c = c ;
temp.next = b ;
edge[a].push_back(temp);
temp.next = a ;
edge[b].push_back(temp);
}
//初始化所有的路径都不可通过,所有的点都没有被拥有
for(int i = 0 ; i <= n ; i++)
{
Dis[i] = -1 ;
mark[i] = false;
}
//一开始从结点1开始
Dis[1] = 0 ;
mark[1] = true ;
int newP = 1 ;
//对于结点1到结点n,每一次循环都可以找出一个未访问过的最短路径,所以,n-1次循环就可以
//将Dis[n]数组完全填满
for(int i = 1 ; i < n ; i ++)
{
for(int j = 0 ; j <edge[newP].size() ; j++)
{
int t = edge[newP][j].next ;
int c = edge[newP][j].c ;
if(mark[t] == true) continue ;
if(Dis[t] == -1 || Dis[t] > Dis[newP] + c)
Dis[t] = Dis[newP] + c ;
}
int min = INT_MAX ;
for(int j = 1 ; j <= n ; j++)
{
if(mark[j] == true) continue ;
if(Dis[j] == -1) continue ;
if(Dis[j] < min )
{
min = Dis[j] ;
newP = j ;
}
}
mark[newP] = true ;
}
}
}
未完待续......