弗洛伊德算法是求最小路径的很好算法,但算法要求的时间复杂度很高,当结点少得时候可以用:
问题描述:已知一个含有n个顶点的各边权值均大于0的带权有向图,对每对顶点vi!=vj,要求求出每一对顶点之间的最短路径和最短路径长度。
解决方案:弗洛伊德(floyd)算法
A0
|
1
|
2
|
3
|
|
A1
|
1
|
2
|
3
|
1
|
0
|
4
|
5
|
|
1
|
0
|
4
|
5
|
2
|
2
|
0
|
6
|
|
2
|
2
|
0
|
min(6,2+5)
|
3
|
2
|
2
|
0
|
|
3
|
2
|
min(2,2+4)
|
0
|
A2
|
1
|
2
|
3
|
|
A3
|
1
|
2
|
3
|
1
|
0
|
4
|
min(5,4+6)
|
|
1
|
0
|
min(4,5+2)
|
5
|
2
|
2
|
0
|
6
|
|
2
|
min(2,6+2)
|
0
|
6
|
3
|
min(2,2+2)
|
2
|
0
|
|
3
|
2
|
2
|
0
|
这里的Ai即为用i做中间量时,x到y的最短路径(最小值),如A1即为当用1做中间值时,2-3,3-2的最小值,这样当运行到A3时,每个x到每个y的最短路径都以求出来了,这时,每行中的最大值即为该行算代表的数走完全部支点的值(当为无穷大时(这里无穷取1200即可),说明走不通),在把每行最大值求最小值,即为问题解。
核心代码:
最后根据题意,取每行最大值中的最小值即可。
注意:要把对角线上的数值进行特殊处理,把它们都至为0.而走不到的就置为1200。
代码:
#include<stdio.h>
#include<memory.h>
main(){
int i,n;
int a[101][101],max,m[101],flag,j,k,a1,n1,b;
int min;
while(scanf("%d",&n)&&n){
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=(i==j)?0:-1; //出对角线外,其它都只为-1,对角线值为0;
for(i=1;i<=n;i++){
scanf("%d",&n1);
while(n1--){
scanf("%d%d",&a1,&b);
a[i][a1]=b;
}
}
for(k=1;k<=n;k++){
for(j=1;j<=n;j++)
if(a[k][j]==-1)
a[k][j]=1200; //两点之间没有路径,则值置为1200(无穷大的意思);
}
for(i=1;i<=n;i++)
for(k=1;k<=n;k++)
for(j=1;j<=n;j++)
a[k][j]=(i==k||i==j||k==j)?a[k][j]:((a[k][j]<(a[k][i]+a[i][j])?a[k][j]:(a[k][i]+a[i][j]))); //floyd的模板代码
for(i=1;i<=n;i++){
max=0;
for(j=1;j<=n;j++)
max=max>a[i][j]?max:a[i][j];
m[i]=max;
}
flag=0;
min=1200;
for(i=1;i<=n;i++){
if(min>m[i]){
min=m[i];
flag=i;
}
}
if(flag)
printf("%d %d/n",flag,min);
else
printf("disjoint/n");
}
return 0;
}