最短路径问题-Dijstra

最短路径问题

问题来源:hdu-3790


Problem Description
给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
 
Input
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点。n和m为0时输入结束。
(1<n<=1000, 0<m<100000, s != t)
 
Output
输出 一行有两个数, 最短距离及其花费。
 
Sample Input
3 2
1 2 5 6
2 3 4 5
1 3
0 0

Sample Output
9 11

源代码:

#include<stdio.h>
#include<string.h>
#define MAX 1006
#define INF 999999999

int map[MAX][MAX] , cost[MAX][MAX] , mark[MAX] , dis[MAX] , value[MAX];
//map[i][j]存储双向地图,存储i点到j点的距离
//cost[i][j]存储i点到j点的花费
//mark[i]标志i点手否被更新过
//dis[i]是i点到源点s的最短距离
//value[i]是i点到源点s的最短花费

void Dijstra( int map[][MAX] , int N , int s , int t );

int main( ){
	int N , M;
	int a , b , c , d , s , t;

	while( ~scanf("%d%d",&N,&M) && N+M!=0 ){
		for( int i=1 ; i<=N ; i++ )
			for( int j=1 ; j<=N ; j++ ){
				map[i][j] = cost[i][j] = INF;	//输入前初始化
				map[i][i] = cost[i][i] = 0;
			}

		for( int i=1 ; i<=M ; i++ ){
			scanf("%d%d%d%d",&a,&b,&c,&d);
			if( c < map[a][b] ){		//重边长度不等的情况
				map[a][b] = map[b][a] = c;
				cost[a][b] = cost[b][a] = d;
			}	//重边相等长度的情况
			else if( c==map[a][b] && d<cost[a][b] ){
				cost[a][b] = cost[b][a] = d;
			}
		}

		scanf("%d%d",&s,&t);

		Dijstra(map,N,s,t);
	}

	return 0;
}


void Dijstra( int map[][MAX] , int N , int s , int t ){
//算法思路:最短路径递增,只适用于非负权边
	int min , k , last=s;

	memset( mark , 0 , sizeof( mark ) );

	for( int i=1 ; i<=N ; i++ ){
		dis[i] = map[s][i];
		value[i] = cost[s][i];
	}

	mark[s] = 1;	//源点标记

	while( 1 ){
		for( int i=1 , min=INF ; i<=N ; i++ ){	//寻找下一个dis最短的点
			if( mark[i]==0 && dis[i]<min ){
				min = dis[k=i];
			}
		}

		mark[k] = 1;	//标记dis最短的边

		if( k==t ){
			printf("%d %d\n",dis[t],value[t]);
			return ;
		}

		for( int j=1 , min=INF ; j<=N ; j++ ){	//k点来松弛其他节点长度和花费
				if( dis[k] + map[k][j] < dis[j] ){
					dis[j] = dis[k] + map[k][j];
					value[j] = value[k] + cost[k][j];
				}
				else if( dis[k]+map[k][j]==dis[j]  && value[k]+cost[k][j]<value[j] ){
					value[j] = value[k] + cost[k][j];
				}
		}
	}
}
代码分析:采用了Dijstra算法(求单源点到其他点的最短路径),时间复杂度为O(n^2),分为三个步骤:寻找、标记、松弛。

Prim算法与Dijstra算法的区别:Prim是计算最小生成树的算法、Dijkstra是计算最短路径的算法;Prim算法的更新操作更新的cls是已访问集合到未访问集合中各点的距离;Dijkstra算法的更新操作更新的cls是源点到未访问集合中各点的距离,已经访问过的相当于已经找到源点到它的最短距离了;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章