Floyd_Warshall Algorithm
来源:互联网 发布:vs2015 mysql 编辑:程序博客网 时间:2024/06/05 21:09
本算法是对算法导论上相关章节伪代码的实现:
#include<iostream>#include<fstream>#include<algorithm>using namespace std;#define MAX 32767ifstream fin("data.in");int N,M;int u,v,l;int D[1000][1000],p[1000][1000],tmpD[1000][1000],tmpP[1000][1000];void print(int (*arr)[1000]){for(int i=0;i<N;++i){for(int j=0;j<N;++j){if(arr[i][j]==MAX)cout<<"∞"<<"\t";elsecout<<arr[i][j]<<"\t";}cout<<endl;}}void FloydWarshall(){for(int k=0;k<N;++k){for(int i=0;i<N;++i){for(int j=0;j<N;++j){if(D[i][k]<MAX&&D[k][j]<MAX){if(D[i][j]>D[i][k]+D[k][j]){tmpD[i][j]=D[i][k]+D[k][j];tmpP[i][j]=p[k][j];}else{if(tmpD[i][j]>D[i][j]){tmpD[i][j]=D[i][j];tmpP[i][j]=p[i][j];}}}}}swap(D,tmpD);swap(p,tmpP);}}int main(){fin>>N>>M;for(int i=0;i<N;++i){for(int j=0;j<N;++j){D[i][j]=tmpD[i][j]=MAX;p[i][j]=tmpP[i][j]=-1;}D[i][i]=tmpD[i][i]=0;}for(int i=0;i<M;++i){fin>>u>>v>>l;D[u-1][v-1]=tmpD[u-1][v-1]=l;if(l!=MAX)p[u-1][v-1]=tmpP[u-1][v-1]=u;}FloydWarshall();print(D);cout<<"intermedia vertex:"<<endl;print(p);return 0;}
对于两个节点能否连通的代码的实现版:
#include<iostream>#include<fstream>#include<algorithm>using namespace std;ifstream fin("data1.in");#define MAX 32767int N,M;int u,v,l;int D[1000][1000],tmp[1000][1000];void TransitiveClosure(){for(int k=0;k<N;++k){for(int i=0;i<N;++i){for(int j=0;j<N;++j){tmp[i][j]=D[i][j]||(D[i][k]&&D[k][j])||tmp[i][j];}}swap(D,tmp);}}int main(){fin>>N>>M;for(int i=0;i<N;++i){for(int j=0;j<N;++j){D[i][j]=0;}D[i][i]=1;}for(int i=0;i<M;++i){fin>>u>>v>>l;D[u-1][v-1]=1;}TransitiveClosure();for(int i=0;i<N;++i){for(int j=0;j<N;++j)cout<<D[i][j]<<"\t";cout<<endl;}return 0;}
我在看的时候,我就想啊:为什么核心代码
for k <----1 to n
do for i <--- 1 to n
do for j <--- 1 to n
do.......
可以写成这样的呢.
矩阵乘法的核心代码是很好懂的:
for i <--- 1 to n
do for j <--- 1 to n
do for k <--- 1 to n
对于每一对节点,判断k是不是它们的中间节点.
Floyd-Warshell算法把k遍历提到了最前面,以此减少了n次遍历.为什么可以这样呢?
前面的遍历是很好懂的.当D[i][j]>D[i][k]+D[k][j],更新D[i][j].反之就不更新.那么现在问题就来了,如果在后面的遍历中,我们更新了D[i][k],那么还要不要在更新D[i][j]呢.Floyd-Warshell算法告诉我们不需要的.那为什么不需要呢.这个最难懂了.
我对本问题进行了分析,导致D[i][j]不能更新的原因是:D[i][j]<D[i][k]+D[k][j].再后面的遍历中,如果k还能作为D[i][j]的中间节点的话,那么一定更新了D[i][k]或D[k][j],因为每一次只能更新一个,所以D[i][k]和D[k][j]一定在一时间只更新了一个,更新就是减小,那D[i][k]或D[k][j]减小了,为什么不要在更新D[i][j]呢?
我们假设找到了节点m,m对D[i][k]进行了更新,那m一定是i,k的中间节点,D[i][m]就是i,m 的最小距离了,如果不是的话,我们考虑极端情况,m=n-1;这样D[i][m]就是i,m的最小距离了.为什么不在需要k了呢?因为如果k能更新的话,那m也一定能更新.因为D[i][k]=D[i][m]+D[m][k]是i,k 间的最小距离,如果此时D[i][j]=D[i][k]+D[k][j]是i,j间的最小距离,那么一定可以找到D[i][j]=D[i][m]+D[m][j]是i,j间的最小距离.此时k是m,j的中间节点.同样可以考虑极端情况.这样m就代替了k对D[i][j]进行更新,而如果k能进行更新的话,那k一定能在D[i][m]中或D[m][j]中找到.
对D[k][j]采取同样的分析方法.
- Floyd_Warshall Algorithm
- Dijkstra和Floyd_warshall
- 图论--Floyd_Warshall算法---邻接矩阵实现
- UVa10793 - The Orc Attack(floyd_warshall)
- Algorithm
- Algorithm
- algorithm
- algorithm
- algorithm
- algorithm
- algorithm
- Algorithm
- Algorithm
- algorithm
- Algorithm
- Algorithm
- algorithm
- algorithm
- 【控制文件丢失-恢复-1】
- 01(CodeforcesC水平)CQU新生周末狂欢赛O- Pocket Book
- 绑定自定义类到Runtime(Lua-binding)
- 关于判断cpu大端存储还是小端存储的讨论与分析
- 让 table 的 table td边框合并的方法
- Floyd_Warshall Algorithm
- 解决进行Android开发环境搭建时下载速度慢的问题
- LDA文本建模
- 【Cocos2d-x】Lua 资源热更新
- 18周OJ二分法查找元素并输出其位置
- ***UVA12657 Boxes in a Line ACM解题报告(链表)
- AngularJS的MVC浅谈
- 我的UFO观
- 贪吃蛇游戏