编程题—比较重量—Floyd算法实现

内容会持续更新,有错误的地方欢迎指正,谢谢!

何为Floyd算法

是一种利用邻接矩阵记录每两点间的最短路径以在没负回路的有向图中找到最短路径的算法。

求最短路的Floyd算法框架:

声明一个二维数组(官方叫:邻接矩阵),用于将有向图转化为这个二维数组matrix,如何转化?

  1. 先将对角线上的元素置0,非对角线上元素置无穷大;
  2. 再将图中互相相连的两点的距离写入到二维数组中;比如点1到点2的距离为3,则matrix[0][1] = 3;
  3. Floyd登场:见下方 Floyd分析 板块

Floyd分析:

整个算法虽然感觉很麻烦,但其实代码实现却非常简单,核心代码只有五行:

for(k=1;k<=n;k++)   
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
             //k为中转点,matrix[i][k]表示从ik的路径长度
             if(matrix[i][j]>matrix[i][k]+matrix[k][j])
                 matrix[i][j]=matrix[i][k]+matrix[k][j]; 

这五行代码的基本思想:传递思想,或叫中转思想。最开始k=1,只允许经过1号顶点(必须经过1号顶点)进行中转;接下来k=2,允许经过1和2号顶点(必须经过2号顶点)进行中转……最后k=n,允许经过1~n号所有顶点(必须经过n号顶点)进行中转,便可求得任意两点之间的最短路程,至于经不经过除k号顶点以外的顶点,要根据实际输入和每条路径的最短长度的计算结果而定。
用一句话概括:最短路径是从i号顶点到j号顶点只经过前k号点且必经过第k号结点的最短路程。

其实这是一种动态规划的思想,动态规划的特征有两个:

  1. 最优化问题;
  2. 把大问题转化为一系列互相有关系的子问题,子问题的求解依赖于其它子问题的解。

动态规划总结:就是根据每步计算的结果一步步地构造出了最优解决方案。

Floyd算法的应用

全成对问题类型

请见链接里文章的后半部分

比较重量问题类型

题目

小明陪小红去看钻石,他们从一堆钻石中随机抽取两颗并比较她们的重量。这些钻石的重量各不相同。在他们们比较了一段时间后,它们看中了两颗钻石g1和g2。现在请你根据之前比较的信息判断这两颗钻石的哪颗更重。

给定两颗钻石的编号g1,g2,编号从1开始,同时给定关系数组vector,其中元素为一些二元组,第一个元素为一次比较中较重的钻石的编号,第二个元素为较轻的钻石的编号。最后给定之前的比较次数n。请返回这两颗钻石的关系,若g1更重返回1,g2更重返回-1,无法判断返回0。输入数据保证合法,不会有矛盾情况出现。

输入例子:2,3,[[1,2],[2,4],[1,3],[4,3]],4
输出例子:1

分析

依然是Floyd算法的应用,与上个例子的不同点是初始值不同、if条件不同,思路如下:

钻石之间的重量关系是一个有向无环图,可声明一个二维数组(即邻接矩阵),数组元素的两个索引分别代表前一个和后一个钻石的重量,数组元素是1代表前一个钻石的重量大于后一个钻石,是0代表尚未发现前后两个钻石之间的关系。那么,如何将关系转化为数组?

  1. 将对角线上的元素置1,表示自己可到自己;非对角线上的元素置0,表示某点不可到某点;
  2. 根据已有的比较关系,将可比较(即第一个元素可到第二个元素)的两点对应的元素置1,比如:若有[2,1],那2比1重,则有matrix[2][1]=1;
  3. Floyd登场:三个for循环,if(matrix[i][k]==1&&matrix[k][j]==1) matrix[i][j]==1;一波带走!
代码
class Cmp {
public:
    int cmp(int g1, int g2, vector<vector<int> > records, int n) 
    {
        int i,j,k;
        //先要求得最重的那颗钻石,又由于钻石的重量各不相同,所以数组索引为钻石重量。
        int maxNum=0;
        for(i=0;i<n;++i)//由于records,此时i应初始化为0,判断上界为<n
        {
            if(maxNum<records[i][0])
                maxNum=records[i][0];
            if(maxNum<records[i][1])
                maxNum=records[i][1];
        }
        int matrix[maxNum+1][maxNum+1];//多申请一个或几个空间,以便从1开始,更直观。
        for(i=1;i<=maxNum;++i)
            for(j=1;j<=maxNum;++j)
            {
                if(i==j)
                    matrix[i][i]=1;
                else
                    matrix[i][j]=0;
            }
        for(i=0;i<n;++i)//此时i应初始化为0,判断上界为<n,而不是<maxNum
            matrix[records[i][0]][records[i][1]]=1;
        for(k=1;k<=maxNum;++k)
            for(j=1;j<=maxNum;++j)
                for(i=1;i<=maxNum;++i)
                    if(matrix[i][k]==1&&matrix[k][j]==1)
                        matrix[i][j]=1;
        if(matrix[g1][g2]==1)
            return 1;
        else if(matrix[g2][g1]==1)
            return -1;
        return 0;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值