Dijkstra算法浅析

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

结点1到本身结点1的路径为0,到其余的结点路径初始化为-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 ;
		}
	}
}
未完待续......
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值