同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
運行: