Floyed算法(实际是动态规划问题)
问题:权值矩阵matrix[i][j]表示i到j的距离,如果没有路径则为无穷
求出权值矩阵中任意两点间的最短距离
分析:对于每一对定点u,v看是否存在一个点w使从u到w再到v的路径长度比已知路径短
如果有则更新从u到w的距离
参考网页
1:不用状态压缩的动态规划算法:
状态定义:d[1][i][j]表示以1作为媒介时从i到j的最短距离
d[2][i][j]表示以1,2中的点作为媒介时从i到j的最短距离
……
d[n][i][j]表示以1,2, ……n中的点作为媒介时从i到j的最短距离
状态转移方程d[k][i][j] = min(d[k-1][i][j], d[k-1][i][j]+d[k-1][k][j]);
理解为把i到j的路径氛围两种情况,一种不经过k,一种经过k
2:状态压缩表示:
假设用d[i][j]表示从i到j的最短路径
由于d[i][j]在计算中重复使用,因此表示阶段的那一维被取消了
在没有计算出来新的d[i][j]的时候d[i][j]存储的实际是d[k-1][i][j]的值
因此可以省去表示阶段的那一维
状态转移方程:d[i][j] = min(d[i][j], d[i][j]+d[k][j]);
int matrix[M][M]; void floyed_orginal(int n) { for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) d[0][i][j] = matrix[i][j]; } for(int k = 1; k <= n; k++) { for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) d[k][i][j] = min(d[k-1][i][j], d[k-1][i][k]+d[k-1][k][j]); } } } void floyd() { for(int k = 1; k <= n; k++) for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) d[i][j] = min(d[i][j], d[i][k] + d[k][j]); }
路经压缩之前的floyed算法测试代码
/* 本程序中节点标号1,2,……n floyed算法: floyed算法实际上是动态规划, 对于任意两个点u,v,看是否存在一个点w,使得从u到w再到v的距离比从u直接到v的距离短 d[k][i][j]存储从i到j经过1, 2, ……k,的路径中的最短路径 比如d[1][i][j]存存储经过1时从i到j的最短距离 d[2][i][j]存储经过1, 2中的点时时从i到j的最短距离 得到状态转移方程d[k][i][j] = min(d[k-1][i][j], d[k-1][i][k]+d[k-1][k][j]); */ #define M 100 #define INF 0x3f3f3f #include <stdio.h> #include <stdlib.h> #include <algorithm> using namespace std; int d[M][M][M]; int mat[M][M]; int n, m; void FloyedOrginal() { //无论经不经过中间节点,任意两点间的最短距离初始化为无穷 for(int k = 0; k <= n; k++) for(int i = 0; i <= n; i++) for(int j = 0; j <= n; j++) d[i][k][k] = INF; //不经过中间节点的时候两点间的距离初始化为两点间本身的距离 for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) d[0][i][j] = mat[i][j]; //动态规划过程 for(int k = 1; k <= n; k++) for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) d[k][i][j] = min(d[k-1][i][j], d[k-1][i][j]+d[k-1][k][j]); } void Init() { printf("请输入节点的个数 "); scanf("%d", &n); printf("请输入已知数据的组数 "); scanf("%d", &m); for(int i = 0; i <= n; i++) for(int j = 0; j <= n; j++) mat[i][j] = INF; for(int i = 0; i < m; i++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); mat[u][v] = mat[v][u] = w; } } int main() { Init(); FloyedOrginal(); printf("%d", d[n][1][n]); return 0; }
路径压缩之后
/* 本程序中节点标号1,2,……n floyed算法: floyed算法实际上是动态规划, 对于任意两个点u,v,看是否存在一个点w,使得从u到w再到v的距离比从u直接到v的距离短 d[i][j]存储从i点到j点的最短距离 */ #define M 100 #define INF 0x3f3f3f #include <stdio.h> #include <stdlib.h> #include <algorithm> using namespace std; int mat[M][M]; int n, m; void FloyedOrginal() { //用k遍历所有中间节点的可能 for(int k = 1; k <= n; k++) for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) mat[i][j] = min(mat[i][j], mat[i][k]+mat[k][j]);//是否经过k } void Init() { printf("请输入节点的个数 "); scanf("%d", &n); printf("请输入已知数据的组数 "); scanf("%d", &m); for(int i = 0; i <= n; i++) for(int j = 0; j <= n; j++) mat[i][j] = INF; for(int i = 0; i < m; i++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); mat[u][v] = mat[v][u] = w; } } int main() { Init(); FloyedOrginal(); printf("%d", mat[1][4]); return 0; }