1. 程式人生 > >經典演算法之Floyd演算法(求圖中任意一對頂點間的最短路徑)

經典演算法之Floyd演算法(求圖中任意一對頂點間的最短路徑)

/************************
author's email:[email protected]
date:2018.1.30
************************/
/*
佛洛伊德演算法思想:
	1)設定兩個矩陣A和Path,初始時將圖的鄰接矩陣賦值給A,將矩陣Path中元素全部設定為-1
	2)以頂點k為中間頂點,k取0——n-1(n為圖中頂點個位),為圖中所有頂點對{i,j}進行如下檢測與修改:
	如果A[i][j]>A[i][k]+A[k][j],則將A[i][j]改為A[i][k]+A[k][j]的值,將path[i][j]改為k,否則
	什麼都不做。
佛洛伊德演算法的時間複雜度分析:
	由演算法程式碼可知,本演算法的主要部分是一個三層順序,取內層迴圈的操作作為基本操作,則
	基本操作的執行次數為n^3,因此時間複雜度為O(n^3)。
*/
#include<iostream>
#define INF 100//INF為比圖中任何權值都大的數
#define maxSize 4   //圖的頂點數
#define number 8   //圖的邊數
using namespace std;
typedef struct {//圖的定義
	int edges[maxSize][maxSize];//鄰接矩陣的定義
	int n, e;   //分別為頂點數和邊數
}MGraph;
MGraph createGraph(MGraph g);
void Floyd(MGraph g, int A[][maxSize],int path[][maxSize]);//佛洛伊德演算法
void printPath(int u, int v, int path[][maxSize]);/*遞迴輸出從u到v的最短路徑頂點序列*/
int main() {

	MGraph g;//定義並初始化圖g
	g.edges[maxSize][maxSize] = { 0 };
	g.n = maxSize; g.e = number;
	g = createGraph(g);//建立一個圖

	int A[maxSize][maxSize] ;
	int path[maxSize][maxSize] ;
	int u, v;//定義起始點和終點
	u = 1,v=0;

	Floyd(g, A, path);

	cout << "從" << u << "點到" << v << "點的最短路徑為:" << endl;
	cout << u << " ";
	printPath(u, v, path);
	cout << v << endl;

	cout << "從" << u << "點到" << v << "點的最短路徑長度為:" <<A[u][v]<< endl;
	system("pause");
	return 0;
}

MGraph createGraph(MGraph g) {//此圖為一個正方形,按順時針順序圖的各頂點為0,1,2,3
	int i, j;
	for (i = 0; i < maxSize; i++)
	{
		for (j = 0; j < maxSize; j++)
		{
			g.edges[i][j] = INF;
		}
	}
	g.edges[0][1] = 5;
	g.edges[0][3] = 7;
	g.edges[2][0] = 3;
	g.edges[1][2] = 4;
	g.edges[2][1] = 3;
	g.edges[2][3] = 2;
	g.edges[3][2] = 1;
	g.edges[1][3] = 2;
	g.n = maxSize;
	g.e = number;
	return g;
}
void Floyd(MGraph g, int A[][maxSize],int path[][maxSize])
{
	int i, j, k;
	//對陣列A[][]和path[][]進行初始化
	for (i = 0; i < g.n; ++i)
	{
		for (j = 0; j < g.n; ++j)
		{
			A[i][j] = g.edges[i][j];
			path[i][j] = -1;
		}
	}

	/*下面這個三層迴圈是本演算法的主要操作,完成了以k為中間點對所有頂點對{i,j}
	進行檢測和修改*/
	for (k = 0; k < g.n; ++k)
	{
		for (i = 0; i < g.n; ++i)
		{
			for (j = 0; j < g.n; ++j)
			{ 
				if (A[i][j] >( A[i][k] + A[k][j]))
				{
					A[i][j] = A[i][k] + A[k][j];
					path[i][j] = k;
				}
			}
		}
	}
}
void printPath(int u, int v, int path[][maxSize])	/*遞迴輸出從u到v的最短路徑頂點序列*/
{
	if (path[u][v] == -1)
		return;
	else
	{
		cout<< path[u][v] << " ";
		int mid = path[u][v];
		printPath(u, mid, path);//處理mid前半段路徑
		printPath(mid, v, path);//處理mid後半段路徑
	}
}