1 /* 2 INPUT 3 4 5 7 12 6 1 2 24 7 1 3 8 8 1 4 15 9 2 5 6 10 3 5 7 11 3 6 3 12 4 7 4 13 5 7 9 14 6 5 2 15 6 7 3 16 6 4 5 17 7 2 3 18 19 5 20 1 2 21 3 6 22 1 7 23 4 4 24 3 7 25 26 27 OUTPUT 28 29 1 to 2 need 17 30 3 to 6 need 3 31 1 to 7 need 14 32 4 to 4 need 0 33 3 to 7 need 6 34 35 */ 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <algorithm> 40 using namespace std; 41 const int inf=0x3f3f3f3f; 42 int n,m,w[110][110]; 43 int main() 44 { 45 while(~scanf("%d%d",&n,&m)) 46 { 47 memset(w,inf,sizeof(w));//先全部设为无穷大 48 for(int i=1; i<=n; i++) 49 w[i][i]=0;//自己到自己距离为0; 50 while(m--) 51 { 52 int u,v,c; 53 scanf("%d%d%d",&u,&v,&c); 54 if(c<w[u][v]); 55 w[u][v]=w[v][u]=c; 56 } 57 for(int k=1; k<=n; k++)//为了将i,j与k的情况讨论完,k作为中间点,要放在最外层 58 { 59 for(int i=1; i<=n; i++) 60 { 61 for(int j=i+1; j<=n; j++)//因为是无向图,j>i或j<i(2,3),(3,2)的情况是一样的,不用重复计算 62 { 63 if(k!=i&&j!=k&&w[i][k]!=inf&&w[k][j]!=inf)//k作为中间点,三点不能重合,并且要满足k与i,j都有连接 64 { 65 w[i][j]=w[j][i]=min(w[i][j],w[i][k]+w[k][j]);//假如第三点之和小于起点直接到终点之和就更新 66 } 67 } 68 } 69 } 70 scanf("%d",&m); 71 while(m--) 72 { 73 int u,v; 74 scanf("%d %d",&u,&v); 75 printf("%d to %d need %d ",u,v,w[u][v]); 76 } 77 } 78 return 0; 79 }
从任意节点i到任意节点j的最短路径不外乎2种可能,1是直接从i到j,2是从i经过若干个节点k到j。所以,我们假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,我们检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径短,我们便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离。