最短路径问题(Dijkstra解法)

算法分类:

贪心


算法原理:

设置一个顶点的集合s,并不断地扩充这个集合,一个顶点属于集合s当且仅当从源点到该点的路径已求出。开始时s中仅有源点,并且调整非s中点的最短路径长度,找当前最短路径点,将其加入到集合s,直到终点在s中。
基本步骤:
1、把所有结点分成两组:
       第一组:包括已经确定最短路径的结点;
       第二组:包括尚未确定最短路径的结点。
2、开始时,第一组只包含起点,第二组包含剩余的点;
3、用贪心的策略,按最短路径长度递增的顺序把第二组的结点加到第一组去,直到v0可达的所有结点都包含于第一组中。在这个过程中,不断更新最短路径,总保持从v0到第一组各结点的最短路径长度dist都不大于从v0到第二组任何结点的路径长度。
4、每个结点对应一个距离值,第一组结点对应的距离就是v0到此结点的最短路径长度,第二组结点对应的距离值就是v0由第一组结点到此结点的最短路径长度。
5、直到所有的顶点都扫描完毕(v0可达的所有结点都包含于第一组中),找到v0到其它各点的所有最短路径。

如图:求0点到其他点的最短路径。

最短路径问题(Dijkstra解法)_第1张图片最短路径问题(Dijkstra解法)_第2张图片

(1)开始时,s1={v0},s2={v1,v2,v3,v4},v0到各点的最短路径是{0,10,&,30,100};
(2)在还未进入s1的顶点之中,最短路径为v1,因此s1={v0,v1},由于v1到v2有路径,因此v0到各点的最短路径更新为{0,10,60,30,100};
(3)在还未进入s1的顶点之中,最短路径为v3,因此s1={v0,v1,v3},由于v3到v2、v4有路径,因此v0到各点的最短路径更新为{0,10,50,30,90};
(4)在还未进入s1的顶点之中,最短路径为v2,因此s1={v0,v1,v3,v2},由于v2到v4有路径,因此v0到各点的最短路径更新为{0,10,50,30,60};
数据结构:
(1)用一个二维数组a[i..j,i..j]来存储各点之间的距离,10000表示无通路:
(2)用数组dist[i..j]表示最短路径;
(3)用集合s表示找到最短路径的结点。


算法时间复杂度:

O(n平方)


代码实现:hdu2544

/* 最短路径问题 */ 
#include 
using namespace std;

const int INF = 2147483647;
const int SIZE = 105;
int  G[SIZE][SIZE];
int  D[SIZE];
bool vis[SIZE];

void dijkstra(int n, const int src)
{
	int i, v, w, min;
	
	memset(vis, false, sizeof(vis));
	
	for (i = 1; i <= n; ++i)
	{
		D[i] = G[src][i];
	}
	
	vis[src] = true;
	D[src] = 0;
	
	for (i = 1; i <= n; ++i)
	{
		min = INF;
		
		for (w = 1; w <= n; ++w)
		{
			if (!vis[w] && min > D[w])
			{
				v = w;
				min = D[w];	
			}	
		}	
		
		vis[v] = true;
		
		for (w = 1; w <= n; ++w)
		{
			if (!vis[w] && D[w] - min > G[v][w])
			{
				D[w] = G[v][w] + min;
			}	
		}
	}
}

int main()
{
	int a, b, c, i, j, N, M;
	
	while (scanf("%d%d",&N,&M)!=EOF,N&&M) {
		
		for (i = 1; i <= N; ++ i)
			for (j = 1; j <= N; ++ j)
				G[i][j] = INF;
		
		for (i = 0; i < M; ++ i) {
			scanf("%d%d%d",&a,&b,&c);
			if (G[a][b] > c) {
				G[b][a] = c;
				G[a][b] = c;	
			}	
		}
		
		if (N == 1) {
			printf("0\n");
			continue;
		}
		
		dijkstra(N, 1);
		printf("%d\n",D[N]); 	
	}
}


你可能感兴趣的:(算法与数据结构)