Graph图论
Floyed算法(任意两点间的最短路)
可以处理存在负边的情况,也可以判断是否存在负环。
对于最短路我们之前接触的都是单源最短路径,即起点固定,求该点开始到其他点的最短路径,但是如果我们想要求得任意两点间的最短路径,难道要对每一个点都要进行一遍dijkstra?显然比较麻烦,并且还不好存储信息,那么我们就要用到Floyed算法了。
在这里我们用到一个dp数组dp[ i ][ j ]:从 i 到 j 所需要的最短距离,其实把数组的作用想明白了算法也就完成了大半,那么我们假设有一个点k,那么我们从 i 到 j 可以有两种情况,一种是最短路径上经过 k再到 j ,一种是不经过 k ,那么动态转移方程就很好写了:
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]
想好动态数组和动态转移方程,那么就只剩下初始化了,因为最开始的时候我们有的是一条条直达的道路,假设我们知道a->b的路程是c,那么我们初始化的时候就让dp[a][b] = c;
,其余不能直达的就初始化为INF,即dp[a][d] = INF;
自己到自己的距离为0,即dp[i][i] = 0;
Floyed算法跟Bellman_Ford一样,都可以处理负边权的问题,并且判断图中是否存在负环只需要检查是否存在dp[i][j]是负数的边就好了。
完整代码如下:
#include<iostream>
#include<cstring>
using namespace std;
long long dp[10001][10001];
void floyed(int n){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dp[i][j] = min(dp[i][j],dp[i][k]+dp[k][j]);
}
}
}
}
int main(){
int n,m;
cin >> n >> m;
memset(dp,0x7f7f7f7f,sizeof(dp));
for(int i=1;i<=n;i++){
dp[i][i] = 0;
}
for(int i=0;i<m;i++){
int a,b;
long long c;
cin >> a >> b >> c;
dp[a][b] = min(dp[a][b],c);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout << dp[i][j] << " ";
}
cout << endl;
}
floyed(n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout << dp[i][j] << " ";
}
cout << endl;
}
return 0;
}