最短路徑之Floyd-Warshell算法

同Bellman-Ford算法一樣,Floyd Warshell算法同業可以處理帶有負權(但不含負權迴路)的圖的最短了路徑問題。不過該算法並不是單源路徑算法,它運行一次計算的是所有兩個頂點間的最短路徑,時間複雜度爲Theta(n^3)。通過改進,可以打印所有路徑(一般保存路徑會增加空間複雜度)。打印的算法通過保存任意兩個節點之間通過的index爲最大值的節點。


開始吧,floyd算法。


/*
 * szl_floyd_warshell.h
 */
#ifndef SZL_FLOYD_WARSHELL_H
#define SZL_FLOYD_WARSHELL_H

void szl_floyd_warshell(int* graph[], int n);
#endif

/*
 * szl_floyd_warshell.c
 */
#include "szl_floyd_warshell.h"
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

void szl_floyd_warshell(int* graph[], int n);
static void print_one_path(int *dist[], int *next[], int i, int j);


int main( int argc ,char ** argv){
	int **graph;
	int i,j;
	int u,v,w;
	/*
	 * the number of nodes and vertices
	 */
	int n,m;

	/*
	 * read from a file in the current directory named 'data.txt'
	 */
	FILE* data_file;
	
	if( 1 == argc){
		data_file=fopen("data.txt", "r");
	}
	else{
		data_file=fopen(argv[1], "r");
	}
	assert(NULL!=data_file);

	//printf("input vertices and edges.\n");
	fscanf(data_file,"%d%d",&n,&m);
	
	/*
	 * implement a graph with matrix
	 */
	graph=(int **)malloc(sizeof(int *) * n);
	assert(NULL != graph);
	for(i=0;i<n;i++){
		graph[i]=(int *)malloc(sizeof(int)*n);
		assert(NULL!=graph[i]);
	}
	
	/*
	 * initialization the weight of the graph with a value which means this edge is not exists.
	 */
	for(i=0;i<n;i++){
		for(j=0;j<n;j++){
			graph[i][j]=INT_MAX;
		}
	}

	/*
	 * input the edge and its weight
	 */
	for(i=0;i<m;i++){
		fscanf(data_file,"%d%d%d",&u,&v,&w);
		graph[u][v]=w;
	}

	/*
	 * call the dijkstra to address it
	 */
	szl_floyd_warshell(graph, n);

	/*
	 * close the input stream and free the memory allocated manually.
	 */
	fclose(data_file);
	for(i=0;i<n;i++){
		free(graph[i]);
	}
	free(graph);

	return 0;
}

void szl_floyd_warshell(int* graph[], int n){
	int **dist;
	int **next;

	int i,j,k;
	/*
	 * memory allocated
	 */
	dist = (int **)malloc(sizeof(int *)*n);
	next = (int **)malloc(sizeof(int *)*n);
	for(k=0;k<n;k++){
		dist[k] = (int *)malloc(sizeof(int)*n);
		next[k] = (int *)malloc(sizeof(int)*n);
	}

	/*
	 * initialization 1
	 */
	for(i=0;i<n;i++){
		for(j=0;j<n;j++){
			next[i][j] = -1; //Undefined
			dist[i][j] = INT_MAX; // this statement is optional
		}
	}
	/*
	 * initialization 2
	 * for each vertex, the shortest path is zero
	 */
	for(k=0;k<n;k++){
		dist[k][k] = 0; // this is optional
	}
	/*
	 * initialization 3
	 * for each edge (u,v), the distance from  u to v is  initialized as the weight of edge (u,v)
	 */
	for(i=0;i<n;i++){
		for(j=0;j<n;j++){
			if(graph[i][j] != INT_MAX){
				dist[i][j] = graph[i][j];
			}
		}
	}

	for(k=0;k<n;k++){
		for(i=0;i<n;i++){
			for(j=0;j<n;j++){
				if(dist[i][k] < INT_MAX && dist[k][j] < INT_MAX){
					if(dist[i][j] == INT_MAX){
						next[i][j] = k;
						dist[i][j] = dist[i][k] + dist[k][j];
					}
					else{
						if(dist[i][j] > dist[i][k]+dist[k][j]){
							next[i][j] = k;
							dist[i][j] = dist[i][k] + dist[k][j];
						}	
					}
				}	
			}
		}
	}
	/*
	 * paths
	 */
	for(i=0;i<n;i++){
		for(j=0;j<n;j++){
			if(i!=j){
				printf("[%d][%d]",i,j);
				if(dist[i][j] == INT_MAX){
					printf(": 沒有路徑.");
				}
				else{
					printf(", 距離爲: %d.",dist[i][j]);
					printf("\n");
					if(next[i][j] == -1){
						printf("        這是一條邊.");
					}
					else{
						printf("        途徑節點:");
						print_one_path(dist, next, i, j);
					}
				}
				printf("\n");
			}
		}
	}
	
	for(k=0;k<n;k++){
		free(dist[k]);
		free(next[k]);
	}
	free(dist);
	free(next);
}

static void print_one_path(int *dist[], int *next[], int i, int j){
	int immediate;
	if(dist[i][j] == INT_MAX){
		printf("no path.");
		return;
	}
	immediate = next[i][j];
	if(-1 == immediate){
		return;
	}
	else{
		print_one_path(dist,next,i,immediate);
		printf("[%d]",immediate);
		print_one_path(dist,next,immediate,j);
	}
	
}


下面是測試文件szl_test_floyd_warshell.txt

4 5
0 2 -2
1 0 4
1 2 3
2 3 2
3 1 -1
0 3

也就是wiki的這張圖:


運行結果:


另外一個測試文件:szl_test_bellman_ford.txt

9 16
0 1 9
0 2 7
0 3 4
1 4 -4
2 3 -4
2 5 3
3 1 5
3 4 3
3 6 2
4 6 -2
4 8 -3
5 3 -8
5 7 -3
6 7 5
6 8 2
7 8 -7
0 8


運行:


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