版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_42606750/article/details/88910878
全点对最短路径问题
对于给定的图G(V,E),求出图中任何点对之间的最短距离。
已知:
W[i][j]表示在图上i和j两个结点的距离。INF表示无穷大。
L[i][j]表示从结点i到结点j的最短距离。
b[i][j]表示求从结点i到结点j的最短路径时,结点j的父节点。
算法实现
首先,假设对于每条路径而言,最多只有一条边,L(1)表示每条路径最多只有一条边时的结果,则有L(1)=W。
接着,求出每条路径最多有2,3,4。。。n-1条边时的结果。
很明显,我们可以得到一个结论:L(m)[i][j]=min{L(m-1)[i][k]+W[k][j]},其中k可取的值为0~n-1.
#include <stdio.h>
#include <stdlib.h>
#define INF 90
const int n=5;
int w[n][n] =
{
{0,3,8,INF,-4},
{INF,0,INF,1,7},
{INF,4,0,INF,INF},
{2,INF,-5,0,INF},
{INF,INF,INF,6,0}
};
int **L;
int b [n][n];
int ** extend(int **old,int m){
int **l = (int **)malloc(n*sizeof(int *));
for(int i=0;i<n;i++){
l[i]=(int *)malloc(n*sizeof(int));
}
int x[n][n];
int min = INF;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
l[i][j]=INF;
for(int k=0;k<n;k++){
if(old[i][k]+w[k][j]<=l[i][j]){
l[i][j] = old[i][k]+w[k][j];
min = k;
}
}
if(min!=j) x[i][j] = min;
else if(m!=1)x[i][j] = b[i][j];
else x[i][j] = i;
}
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
b[i][j] = x[i][j];
}
}
return l;
}
void print (int i,int j){
if(i==j){
printf("%d ",i+1);
}
else if(b[i][j] == INF){
printf("No path.");
}
else{
print(i,b[i][j]);
printf("%d ",j+1);
}
}
int main(void){
L = (int **)malloc(n*sizeof(int *));
for(int i=0;i<n;i++){
L[i]=(int *)malloc(n*sizeof(int));
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
L[i][j] = w[i][j];
b[i][j] = INF;
}
}
int m = 1;
while(m<n-1){
L = extend(L,m);
m ++;
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
printf("%2d ",L[i][j]);
}
printf("\n");
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
printf("%d ",b[i][j]+1);
}
printf("\n");
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
printf("%d-->%d:",i+1,j+1);
print(i,j);
printf("\n");
}
}
}
优化
上面讲的方法,最终时间复杂度为O(n^4),我们可以通过加快m的递增来减少时间复杂度。
具体方法:每一次递增,m不是加1,而是变成2m。这样一来,算法的实现可以改为:
L(2m)[i][j]=min{L(m)[i][k]+L(m)[k][j]}.
同样,代码也可以做出如下修改:
#include <stdio.h>
#include <stdlib.h>
#define INF 1<<20
const int n=5;
int w[n][n] =
{
{0,3,8,INF,-4},
{INF,0,INF,1,7},
{INF,4,0,INF,INF},
{2,INF,-5,0,INF},
{INF,INF,INF,6,0}
};
int **L;
int b [n][n];
int ** extend(int **old,int m){
int **l = (int **)malloc(n*sizeof(int *));
for(int i=0;i<n;i++){
l[i]=(int *)malloc(n*sizeof(int));
}
int x[n][n];
int min = INF;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
x[i][j] = b[i][j];
}
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
l[i][j] = INF;
for(int k=0;k<n;k++){
if(old[i][k]+old[k][j]<=l[i][j]){
l[i][j] = old[i][k]+old[k][j];
if(m == 1){
min = k;
}
else min = b[k][j];
}
}
if(min!=j) x[i][j] = min;
else if(m!=1)x[i][j] = b[i][j];
else x[i][j] = i;
}
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
b[i][j] = x[i][j];
}
}
return l;
}
void print (int i,int j){
if(i==j){
printf("%d ",i+1);
}
else if(b[i][j] == INF){
printf("No path.");
}
else{
print(i,b[i][j]);
printf("%d ",j+1);
}
}
int main(void){
L = (int **)malloc(n*sizeof(int *));
for(int i=0;i<n;i++){
L[i]=(int *)malloc(n*sizeof(int));
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
L[i][j] = w[i][j];
b[i][j] = INF;
}
}
int m = 1;
while(m<n-1){
L = extend(L,m);
m = 2*m;
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
printf("%2d ",L[i][j]);
}
printf("\n");
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
printf("%d ",b[i][j]+1);
}
printf("\n");
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
printf("%d-->%d:",i+1,j+1);
print(i,j);
printf("\n");
}
}
}
版权声明:本文为CSDN博主「鲸羽」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42606750/article/details/88910878