Floyd(动态规划)求解任意两点间的最短路径(图解)
Posted TomoyaAT的技术分析屋~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Floyd(动态规划)求解任意两点间的最短路径(图解)相关的知识,希望对你有一定的参考价值。
Floyd算法的精髓在于动态规划的思想,即每次找最优解时都建立在上一次最优解的基础上,当算法执行完毕时一定是最优解
对于邻接矩阵w,w保存最初始情况下任意两点间的直接最短距离,但没有加入中继点进行考虑
如w[1][2]=20,即表示点1与点2的当前最短距离(直接距离)为20
对于路径矩阵path,保存了点i到点j的最短路径中下一个点的位置,
如path[1][2]=0,表示1->2的路径中的下一个点为结点0
Floyd算法对所有中继点在任意两点中进行循环遍历.即k从0-n时考虑(i->k,k->j)的路径是否小于(i->j)的路,如果小于即更新邻接矩阵w的值与path矩阵中的值,使其始终保持最短
图解如下:
代码用例:
代码如下
点击查看代码
#include<iostream>
#include<fstream>
#include<vector>
using namespace std;
const int MAX = 999;
class Solution {
public:
void GetPath(vector<vector<int>>vec,int n) {
vector<vector<int>>path(n);
//初始化
for (int i = 0; i != n; i++)
path[i].resize(n);
for(int i=0;i!=n;i++)
for (int j = 0; j != n; j++) {
if (vec[i][j] != MAX)path[i][j] = j;
else path[i][j] = -1;
}
for (int i = 0; i < n; i++)path[i][i] = -1;
for(int k=0;k!=n;k++)
for(int i=0;i!=n;i++)
for (int j = 0; j != n; j++) {
if (vec[i][k] + vec[k][j] < vec[i][j]) {
vec[i][j] = vec[i][k] + vec[k][j];
path[i][j] = path[i][k];
}
}
for (int i = 0; i != n; i++)
{
cout << "\\nStating from vertex: " << i << endl;
bool flag = 0;
for (int j = 0; j != n; j++)
if (j != i && vec[i][j] < MAX) {
flag = 1;
cout << i << "->" << j << ":distance=" << vec[i][j] << ": " << i;
int k = path[i][j];
while (k != j) {
cout << "->" << k;
k = path[k][j];
}
cout << "->" << j << endl;
}
if (!flag)cout << "there\'s no path while starting from "<<i<<endl;
}
}
};
int main() {
ifstream putIn("D:\\\\Input.txt", ios::in);
int num;
int finalCount = 0;
putIn >> num;
const int x = num;
vector<vector<int>>myVector(num);
//myVector:带权邻接矩阵
for (int i = 0; i < num; i++)
myVector[i].resize(num);
for (int i = 0; i < num; i++)
for (int j = 0; j < num; j++) {
int temp;
putIn >> temp;
myVector[i][j] = temp;
}
Solution solution;
cout << "Input文件中的邻接矩阵为\\n";
for (auto x : myVector) {
for (auto y : x)cout << y << \'\\t\';
cout << endl;
}
solution.GetPath(myVector,num);
return 0;
}
我是一个还没有想好写点啥的小尾巴
任意两点间的最短路问题 Floyd-Warshall算法
这一算法与之前的Bellman-F=Ford算法一样,都可以判断负环
只需要检查dp [i] [j] 是负数的顶点i即可
1 // 求解任意两点间的最短路径问题 2 // Floyed-Warshall算法 3 // 复杂度O(N^3),N为顶点数 4 5 #include <cstdio> 6 #include <iostream> 7 8 using namespace std; 9 // 用dp的思路来求解 10 // dp[k][i][j]:从i到j,只利用前K个节点的最短路 11 // dp[k][i][j]=dp[k-1][i][k] + dp[k-1][k][j] 12 // 由于后一层所需的,都来自前一层,而前一层所需 13 // 然后在考虑循环顺序,定k,并且维护最小,所以中间元素必定使用之前维护的在k行k列的元素 14 // 而维护最小值时,k行k列元素,在循环中,加和一定大于原来的值(否则存在d[i][j]<0,存在负圈) 15 // 所以维护最小值时不更新,依旧是上一列表中的值 16 // 所以dp数组可以降维进行运算 17 18 const int max_N = 200+2; 19 const int max_E = 10000+2; 20 const int INF = 1e9; 21 22 int dp[max_N][max_N]; 23 int N,E; 24 25 void floyd_warshall() 26 { 27 for(int k=0;k<N;++k) 28 { 29 for(int i=0;i<N;++i) 30 { 31 for(int j=0;j<N;++j) 32 { 33 dp[i][j]=min( dp[i][j],dp[i][k]+dp[k][j] ); 34 } 35 } 36 } 37 } 38 39 int main() 40 { 41 scanf("%d %d",&N,&E); 42 int a,b,c; 43 for(int i=0;i<N;++i) 44 { 45 for(int j=0;j<N;++j) 46 { 47 if(i==j) 48 { 49 dp[i][j]=0; 50 } 51 else 52 { 53 dp[i][j]=INF; 54 } 55 } 56 } 57 for(int i=0;i<E;++i) 58 { 59 scanf("%d %d %d",&a,&b,&c); 60 dp[a][b]=c; 61 // 无向图 62 dp[b][a]=c; 63 } 64 floyd_warshall(); 65 66 for(int i=0;i<N;++i) 67 { 68 for(int j=0;j<N;++j) 69 { 70 printf("%d ",dp[i][j]); 71 } 72 printf(" "); 73 } 74 return 0; 75 } 76 /* 77 7 10 78 0 1 2 79 0 2 5 80 1 2 4 81 1 3 6 82 1 4 10 83 2 3 2 84 3 5 1 85 4 5 3 86 4 6 5 87 5 6 9 88 89 90 91 92 0 2 5 7 11 8 16 93 2 0 4 6 10 7 15 94 5 4 0 2 6 3 11 95 7 6 2 0 4 1 9 96 11 10 6 4 0 3 5 97 8 7 3 1 3 0 8 98 16 15 11 9 5 8 0 99 */
以上是关于Floyd(动态规划)求解任意两点间的最短路径(图解)的主要内容,如果未能解决你的问题,请参考以下文章