实用算法实现-第 21 篇 每对顶点间的最短路径

21.1    每对顶点间最短路径与矩阵乘法

    考虑矩阵乘法D*D,有:

d’’(i, j) = ∑(d’ (i, k) * d’ (k, j))

    考虑有向图每对顶点间的距离邻接矩阵。w(i, j)为由i点都j点的路径距离。故此有矩阵W的i行向量为i到点集合{j, 1≤j≤n}的距离。而矩阵W的j列向量为点集合{i, 1≤i≤n}到j的距离。

    要求最短路径,可以先考虑某一个点i到j的较短路径的求法。由i点到j点,可以通过点集合{k, 1≤k≤n}中任意一点作为中间结点。i通过这些中间点到达j的最短路径就是一条较短的路径。故此i到j的较短路径长度为:

    W’’(i, j) = min(w’ (i, k) + w’ (k, j))

    可以发现上述两式子的相似之处,将‘+’看做‘*’,将‘min’看做‘∑’。可以将求每对顶点间的最短路径问题转化为矩阵乘法。

    由于这里i到j的这条较短路径只是经过一个中间结点的最短路径,所以不一定是图的最短路径。可以知道i到j的最短路径最多需要进过n-1个中间结点,所以需要重复上述运算log(n-1)次即可。

    朴素的矩阵乘法可以在O(n^3)时间内完成,故此该算法的复杂度为O(n^3*log(n))。虽然这种算法较之Floyd-Wallshall算法的O(n^3)要差,但是这种算法可能在并行计算机中能被很好地优化,因为矩阵乘法在并行计算机中有很多优化办法。

21.2    Floyd-Warshall算法

21.2.1   实例

PKU JudgeOnline, 3660, Cow Contest.

21.2.2   问题描述

给出n只奶牛,如果奶牛a的技能值比奶牛b大,那么a就能打败b,现在给出n只奶牛中m对奶牛的技能。对比情况,输出能确定多少只奶牛的排名。

21.2.3   输入

55

43

42

32

12

2 5

21.2.4   输出

2

21.2.5   分析

某只奶牛能否确定其排名,只要能被它打败的奶牛数加上能打败它的奶牛数等于n-1就可用图的语言描述就是顶点的出度加上这个顶点的入度等于n-1(如果顶点i和顶点j能过通过顶点k相连,那么就把顶点k和顶点i相连)。

21.2.6   程序

#include <stdio.h>
#include <string.h>
int main()
{
     boolhash[101][101],map[101][101];
     int n,m;
     int i,j,k;
     scanf("%d%d",&n,&m);
     memset(hash,false,sizeof(hash));
     memset(map,false,sizeof(map));
     for(i=0;i<m;i++)
     {
         inta,b;
         scanf("%d%d",&a,&b);
         hash[a][b]=true;
         map[b][a]=true;
     }
     for(k=1;k<=n;k++){
         for(i=1;i<=n;i++){
              for(j=1;j<=n;j++)
              {
                   hash[i][j]=hash[i][j]||hash[i][k]&&hash[k][j];
                   map[i][j]=map[i][j]||map[i][k]&&map[k][j];
              }
         }
     }
     intmax,min;
     int c=0;
     for(i=1;i<=n;i++)
     {
         max=min=0;
         for(j=1;j<=n;j++)
         {
              if(i==j)
                   continue;
              if(map[i][j])
                   min++;
              if(hash[i][j])
                   max++;
         }
         if(max+min==n-1)
              c++;
     }
     printf("%d\n",c);
     return 0;
}

21.3    实例

PKU JudgeOnline, 3660, Cow Contest.

本文章欢迎转载,请保留原始博客链接http://blog.csdn.net/fsdev/article

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值