Dijkstra算法 计算有向图的最短路径

baike 2020-05-19

自然语言描述

  1. 定义三个数组,分别为

    V:表示所有的顶点集
    
    D:表示从起始点到其他各点的距离
    
    S:为已求得的从源点出发的最短路径长度的顶点的集合
  2. 设v0为起始点,若与v0直接连接的vi,则记录其权值到D[i],否则记录∞到D[i];

  3. 循环下列语句直至V-S为空集:

(1)遍历D中的数据,若D[i]为最小值;记录vi到S中

(2)更新D中的数据(遍历vj∈(V-S), D[ j ] = MIN(D[ j ] , D[ i ] + D[vi到vj的距离] ));

伪代码

算法:Dijkstra(G,v)v是起始点
 输入:G=(V,E)是带权连通图
 输出:D是含有起始点v到各点最短距离的数组
 过程:
 #define INF 0x7f7f7f7f
 S ← { }
 for i ←1 to |V| :
 	D[i] = INF
 for every vi in V except v:
 	D[i] = min{ 所有的E(v , vi)};
 while(|V-S| != 0){
 	//遍历D中数据
 	vk = min{every D[i] in D};
 	S ← v[k]
 	//更新D中数据
 	for every D[i] in D:
 	D[i] = min{D[i], D[k] + E(k,i) };
}
 输出D

问题

Problem

Given a directed graph, compute all the shortest paths from the source to other vertices.

Input

The first line is the number of test cases.

For every test case, the first line is the number of node n, meaning nodes are 1,2,…,n.

The next line is the number of edges m, then m lines are followed, where each line is in the form of u v w, meaning (u,v) is an edge and it has weight w (>0).

The last line is the source vertex.

Output

For each test case, print all the shortest paths from the source s to other vertices (if the shortest path is finite) in the order of vertices in the following form (no spaces between):

s-1:d1

s-2:d2

Sample Input

2
2
1
1 2 5
1
5
6
1 2 4
1 3 6
2 3 1
4 5 1
3 1 1
5 4 2
2

Sample Output

1-1:0
1-2:5
2-1:2
2-2:0
2-3:1

代码实现

#include <stdio.h>
#define INF 0x7f7f7f7f
#define SIZE 100 
void Dijkstra(int matrix[][SIZE],int vertex, int dis[],int startingpoint);
int min(int a, int b)return a>b?b:a;
int  mindis(int dis[],int vertex,int usedvertex[]);
int main(){
	int times; //次数
	scanf("%d",&times);
	for(int t = 0; t < times; t++){
		int vertex = 0; // 点数
		int edge = 0; // 边数
		scanf("%d",&vertex);
		scanf("%d",&edge);
		int matrix[SIZE][SIZE];
		for(int i = 0; i <= vertex; i++){
		 	for(int j = 0; j <= vertex; j++){
		 		matrix[i][j] = INF;
			 }
		 }
			//输入矩阵 
		 for(int i = 0; i < edge; i++ ){
		 	int x,y,weight;
		 	scanf("%d",&x);
		 	scanf("%d",&y);
		 	scanf("%d",&weight);
		 	if(weight < matrix[x][y]){
		 		matrix[x][y] = weight;
			 }
		 }
		 int startingpoint;
		 scanf("%d",&startingpoint);
		 //distance 数组
		 int dis[vertex+1] ={0};
		 for(int i = 1; i <= vertex; i ++){
		 	dis[i] = matrix[startingpoint][i];
		 } 
        
		 //Dijkstra
		 Dijkstra(matrix,vertex,dis,startingpoint); 
		 //输出
		 for(int i = 1; i <= vertex; i++){
		 	if(dis[i]!=INF)printf("%d-%d:%d\n",startingpoint,i,dis[i]);
		 }
	} 
}
//返回dis数组里的未被记录的最小值
int  mindis(int dis[],int vertex,int usedvertex[]){
	int min=INF, minvertex;
	for(int i = 1 ; i <= vertex; i++){
		if(usedvertex[i]==1)continue;
		if(dis[i]<min){
			min = dis[i];
			minvertex = i;
		}
	}
	return minvertex;
}
void Dijkstra(int matrix[][SIZE],int vertex, int dis[],int startingpoint){
	int usedvertex[vertex+1] = {0}; //记录已确定最小值的点 
	int count = vertex-1;
	usedvertex[0] = 1;
	usedvertex[startingpoint] = 1;
	while(count !=0 ){
		//第一步,取新的点 
		int newvertex = mindis(dis,vertex,usedvertex);
		usedvertex[newvertex] = 1;
		//第二部,更新距离数组 
		for(int i = 1; i <= vertex; i++){
			dis[i] = min(dis[i],matrix[newvertex][i]+dis[newvertex]);
		}
		count --;
	}
	dis[startingpoint] = 0;
}