HDU 最短路径 floyd算法

最短路

Time Limit : 5000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 1   Accepted Submission(s) : 0
Problem Description
在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?

 

Input
输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。 输入保证至少存在1条商店到赛场的路线。
 

Output
对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间
 

Sample Input
 
 
2 1 1 2 3 3 3 1 2 5 2 3 5 3 1 2 0 0
 

Sample Output
 
 
3 2

   

核心思路

编辑

路径矩阵

通过一个图的权值 矩阵求出它的每两点间的 最短路径矩阵。  [3]  
从图的带权 邻接矩阵A=[a(i,j)] n×n开始, 递归地进行n次更新,即由矩阵D(0)=A,按一个公式,构造出矩阵D(1);又用同样地公式由D(1)构造出D(2);……;最后又用同样的公式由D(n-1)构造出矩阵D(n)。矩阵D(n)的i行j列元素便是i号顶点到j号顶点的最短路径长度,称D(n)为图的 距离矩阵,同时还可引入一个后继节点矩阵path来记录两点间的最短路径。
采用松弛技术( 松弛操作),对在i和j之间的所有其他点进行一次松弛。所以时间复杂度为O(n^3);

状态转移方程

状态转移方程如下: map[i,j]:=min{map[i,k]+map[k,j],map[i,j]};
map[i,j]表示i到j的最短距离,K是穷举 i,j的断点,map[n,n]初值应该为0,或者按照题目意思来做。
当然,如果这条路没有通的话,还必须特殊处理,比如没有map[i,k]这条路。
这是我通过百度百科找到的一些核心思路。大家可以自行了解一下,百度百科的解释。下面是我对Floyd算法的理解。

首先,我们在找1到n的最短时间时,最短时间可能是1直接到n点的时间,也可能是1经过多个点再到n点的时间。

如图;求1到4的最短时间,指向4的有1,3两个点。指向3的除了4以外有1,2。而指向2的只有1。所以到达4的路径有(1)1—>4;(2)1—>2—>3—>4;(3)1—>3—>4;三条路径。而(2)和(3)两种路径实际上就是求1到3的最短时间加上3到4的最短时间。所以我们需要知道1到3的最短时间是什么。1到3的路径有(1)1—>2—>3;(2)1—>3;经比较第一条路径时间更短为5;所以1直接4的时间一个为4,经转点到达四的时间为6;经比较走1—>4这条路径时间更短。我们发现在只有一个转点k的情况下只需比较i—>k—>j 和i—>j;如果i—>k—>j 的时间小于i—>j的时间 那么就让i—>j(代表最短时间)的时间等于i—>k—>j ;用一个二维数组表示为if(time[i][j]>time[i][k]+time[k][j])time[i][j]=time[i][k]+time[k][j];

用一个n*n的表格来表示这个二维数组;竖着表示起始位置横着表示终点位置;i=j时距离为0;其中2无法直接到达1,3无法直接到达2,4无法直接到达2,2无法直接到达4所以都设为无穷大。

在只允许经过1号顶点的情况下,任意两点之间的最短路程更新为:

通过上图我们发现:在只通过1号顶点中转的情况下,3号顶点到2号顶点(time[3][2])、4号顶点到2号顶点(time[4][2])以及4号顶点到3号顶点(time[4][3])的路程都变短了。

在只允许经过1和2号顶点的情况下,任意两点之间的最短路程更新为:


通过上图得知,在相比只允许通过1号顶点进行中转的情况下,这里允许通过1和2号顶点进行中转,使得e[1][3]和e[4][3]的路程变得更短了。

同理,继续在只允许经过1、2和3号顶点进行中转的情况下,求任意两点之间的最短路程。任意两点之间的最短路程更新为:

最后允许通过所有顶点作为中转,任意两点之间最终的最短路程为:

上面的图是看一位大佬的。

核心代码:

 
  1. for(k=1;k<=n;k++)   
  2.     for(i=1;i<=n;i++)   
  3.  for(j=1;j<=n;j++)   
  4.      if(time[i][j]>time[i][k]+time[k][j])   
  5.    time[i][j]=time[i][k]+time[k][j]; 

下面出示我的ac代码

 

 #include<iostream>
 #define maxn 9999999;
 using namespace std;
 int time[101][101],i,j,k,n;
 void floyd()
 {
    for(k=1;k<=n;k++)
    for(i=1;i<=n;i++)
    for(j=1;j<=n;j++)
    if(time[i][k]+time[k][j]<time[i][j])
    time[i][j]=time[i][k]+time[k][j];
 }
int main(int argc,char* argv[])
{
    int m,c,a,b;
    while(cin>>n>>m)
    {
        if(n==m&&n==0)break;
        for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        {  
            if(i==j)time[i][j]=0;
            else time[i][j]=maxn;
        }
        for(i=1;i<=m;i++)
        {
            cin>>a>>b>>c;
            time[a][b]=time[b][a]=c;
        }
        floyd();
       cout<<time[1][n]<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值