http://yxwang.spaces.live.com/Blog/cns!BD1957499C10CE30!487.entry
非加权无向图Floyd-Warshall算法优化与改进最近反复用到图的(两两结点)最短路径长度算法,对于非加权、无向图的邻接矩阵,采用经典的Floyd-Warshall算法似乎效率不高。
在网上找了点资料,Valerio Schiavoni的这篇日志有点帮助。简要摘录过来,并统一了符号,校正了错误。
以下代码中, int a[i][j]表示从结点i到j的最短路径长度, n为结点总数。
--------------------------------------------------------------------------------
经典实现
void computeAPSP(const int n) { /* calculate shortest paths from every vertex to every vertex */ for (int k = 0; k < n; k++) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { a[i][j] = min( a[i][j], a[i][k] + a[k][j] ); } } } }
--------------------------------------------------------------------------------
第1次优化: 利用矩阵的对称性
void computeAPSP(const int n) { for (int k = 0; k < n; k++) { for (int i = 0; i < n; i++) { const int a_ki = a[k][i]; for (int j = 0; j < i; j++) { a[i][j] = min( a[i][j], a_ki + a[k][j] ); a[j][i] = a[i][j]; } } } }
--------------------------------------------------------------------------------
第2次优化: 只使用矩阵的下三角部分
void computeAPSP(const int n) { for (int k = 0; k < n; k++) { for (int i = 0; i < n; i++) { if (k != i) { const int a_ki = (k < i) ? a[i][k] : a[k][i]; for (int j = 0; j < min(k, i); j++) a[i][j] = min( a[i][j], a_ki + a[k][j] ); for (int j = k + 1; j < i; j++) a[i][j] = min( a[i][j], a_ki + a[j][k] ); } } } }
--------------------------------------------------------------------------------
第3次优化: 跳过不存在的路径
void computeAPSP(const int n) { for (int k = 0; k < n; k++) { for (int i = 0; i < n; i++) { if (k != i) { const int a_ki = (k < i) ? a[i][k] : a[k][i]; // skip if no path if (a_ki == POSITIVE_INFINITY) continue; for (int j = 0; j < min(k, i); j++) a[i][j] = min( a[i][j], a_ki + a[k][j] ); for (int j = k + 1; j < i; j++) a[i][j] = min( a[i][j], a_ki + a[j][k] ); } } } }
--------------------------------------------------------------------------------
第4次优化: 避免大量调用数学函数
void computeAPSP(const int n) { for (int k = 0; k < n; k++) { for (int i = 0; i < n; i++) { if (k != i) { const int a_ki = (k < i) ? a[i][k] : a[k][i]; // skip if no path if (a_ki == POSITIVE_INFINITY) continue; for (int j = 0; j < min(k, i); j++) { const int s_kj = a_ki + a[k][j]; if( s_kj < a[i][j] ) a[i][j] = s_kj; } for (int j = k + 1; j < i; j++) { const int s_jk = a_ki + a[j][k]; if( s_jk < a[i][j] ) a[i][j] = s_jk; } } } } }