Floyd 算法
问题描述:给定一个带权图(可以有负权),求任意两点间的最短路。
算法过程:
本质是一个动态规划的过程。
G中n个顶点的编号为1到n。令c[i][j][k]表示从i 到j 的最短路径的长度,其中中间顶点不超过k。如果G中包含边<i, j>,则c[i][j][0] =边<i, j> 的长度;否则c[i][j][0]= +∞。c[i][j][n] 则是从i 到j 的最短路径的长度。
对于任意的k>0,通过分析可以得到:中间顶点不超过k的i到j的最短路径有两种可能:该路径含或不含中间顶点k。若不含,则该路径长度应为c[i][j[k-1],否则长度为c[i][k][k-1] +c [k][j][k-1]。c[i][j][k]是两者中的最小值。
状态转移方程:c[i][j][k]=min{ c[i][j[k-1], c[i][k][k-1]+c [k][j][k-1]},k>0。
这样,问题便具有了最优子结构性质,可以用动态规划方法来求解。
for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dist[i][j][k]=MIN(dist[i][j][k-1], dist[i][k][k-1]+dist[k][j][k-1]);
简化即得如下。
具体实现:
void floyd(int n)//floyd算法 { for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (t[i][k]+t[k][j] < t[i][j]) { t[i][j] = t[i][k]+t[k][j]; path[i][j] = k; } }
- for循环不可以改成i,j,k。
- 如需记录路径需增加path,path[i][j] = k表示,i经过k到达j;再递归path[i][k],path[k][i]即可
算法复杂度:O(n^3)
例:POJ 1125 Stockbroker Grapevine
View Code
//POJ 1125 Stockbroker Grapevine //floyd算法 #include <iostream> #include <memory.h> #include <cstdlib> #define MAX_N 100 #define INF 100000 using namespace std; int t[MAX_N][MAX_N];//Note time to send message int max_time(int n, int i)//让所有人收到消息所要时间 { int j; int max = -INF; for (j = 0; j < n; j++) if (t[i][j] > max) max = t[i][j]; return max; } void floyd(int n)//floyd算法,DP { int k, i, j; for (k = 0; k < n; k++) for (i = 0; i < n; i++) for (j = 0; j < n; j++) { if (t[i][k]+t[k][j] < t[i][j]) t[i][j] = t[i][k]+t[k][j]; } } int main(void) { int ns;//number of stockbrokers int nc;//number of people can contact to int min , maxtime_i, min_man; int i, j, k; while (cin >> ns, ns) { memset(t, 1, sizeof(t));//把t[][]全部置成足够大的整数 for (i = 0; i < ns; i++) t[i][i] = 0; for (i = 0; i < ns; i++) { cin >> nc; for (j = 0; j < nc; j++) { cin >> k; cin >> t[i][k-1]; } } floyd(ns); min = INF; for (i = 0; i < ns; i++) { maxtime_i = max_time(ns, i);//让所有人收到消息所要时间 if(maxtime_i < min) { min = maxtime_i; min_man = i + 1;//记录当前最短时间的经纪人号码 } } if (min >= MAX_N)//说明必定有人孤立 cout << "disjoint" << endl; else cout << min_man << " " << min << endl; } return 0; }