2020统考真题-距离最小三元组

2020年统考真题

定义三元组$ (a,b,c)$ ( a,b,c 均为正数)的距离 D = ∣ a − b ∣ + ∣ b − c ∣ + ∣ c − a ∣ D=|a−b|+|b−c|+|c−a| D=ab+bc+ca 。给定 3个非空整数集合 S1 、 S2 和 S3 ,按升序分别存储在 3 个数组中。请设计一个尽可能高效的算法,让算并输出所有可能的三元组 (a,b,c) (其中 a ∈ S 1 , b ∈ S 2 , c ∈ S 3 a∈S1,b∈S2,c∈S3 aS1,bS2,cS3)中的最小距离。例如 S 1 = { − 1 , 0 , 9 } S1=\{−1,0,9\} S1={1,0,9} S 2 = { − 25 , − 10 , 10 , 11 } S2=\{−25,−10,10,11\} S2={25,10,10,11} S 3 = { 2 , 9 , 17 , 30 , 41 } S3=\{2,9,17,30,41\} S3={2,9,17,30,41} ,则最小距离为 2 ,相应的三元组为 ( 9 , 10 , 9 ) (9,10,9) (9,10,9) 。要求:

  1. 给出算法的基本设计思想。
  2. 根据设计思想,采用C或C++语言描述算法,关键之处给出注释。
  3. 说明你所设计算法的时间复杂度和空间复杂度。

设计思想

首先可以设想在一个数轴上,其有三个点分别为a,b,c(从小到大排序,如图)2020统考真题-距离最小三元组_第1张图片

那我们可以得到如下关系:
L 1 = ∣ a − b ∣ L 2 = ∣ c − b ∣ L 3 = ∣ c − a ∣ L 1 + L 2 + L 3 = 2 ∣ c − a ∣ = 2 L 3 L_1 = |a-b|\\ L_2 = |c-b|\\ L_3 = |c-a|\\ L_1+L_2+L_3 = 2|c-a| = 2L_3 L1=abL2=cbL3=caL1+L2+L3=2∣ca=2L3
所以说,三元组中的距离只跟相距最大的两点有关!

所以说,我们想要获取到距离最短,那么改动b的位置是没有用的,甚至会让它距离更远(当b移动到 [ a , c ] [a,c] [a,c]外面以后)

所以我们只能移动a和c

但是由题目可以知道,三个数组中的数据都是按升序排序的,那么这就成为我们优化时间复杂度的一个突破口

都是升序排序。。。。对应到上面那张图就是:所有点只能从左向右移动!

那么在这一限制条件下,我们向右移动c肯定不是一个明智的想法,因为这只会让距离越来越大

那么b不能移动,c也不能移动,那我们只能移动a了,其实想一想,移动a确实可能能让距离更短

其实这道题我们可以想象一下,我们现在有一根橡皮筋,那么距离其实就是固定了橡皮筋a,c以后橡皮筋的长度,而我们要做的就是找出什么时候橡皮筋最松

好,继续说

由于我们上面所说,我们只能向右移动a,但是也有可能a移动太过了,比如超过了b,或者甚至超过了c,那么我们可以给它重新标个号,从左到右重新标为a,b,c

所以说到最后,其实这就变成了一道贪心题,我们不断尝试向右移动最小的那个点,看看能否让距离变短,不能就继续

那我们对比一下暴力求解的算法?

暴力求解时,我们会先固定i,j,然后一个个尝试k( i , j , k i,j,k i,j,k是数组A,B,C的下标, A [ i ] , B [ j ] , C [ k ] A[i],B[j],C[k] A[i],B[j],C[k]是上面所说的变换的a,b,c),但是我们会发现,无论怎么尝试,都只有当 A [ i ] ≤ C [ k ] ≤ B [ j ] A[i]\leq C[k]\leq B[j] A[i]C[k]B[j]时,才是当前状态(指当前固定好的i,j)的最小值,我们假设 A [ i ] ≤ C [ m . . . n ] ≤ B [ j ] A[i]\leq C[m...n]\leq B[j] A[i]C[m...n]B[j],那么m,n里面的比较是毫无意义的,因为我们知道它一定会是最小距离,而我们说了,我们是从左向右遍历序列的,所以我们很清楚,当k遍历到m时,再往后已经没有意义的,所以我们其实已经可以跳出循环了,当然,在固定i,k或者j,k时也是如此,所以我们不如使用三指针,让他们选一个最小的值,让其指针往右走,这才会造成真正我们需要的不同的状态,而不是那些越往后距离越大或者往后也没有变化的状态(这些状态是冗余的,没必要)

简而言之,只让最小的那个值往右走,这才会出现我们需要的尽可能小的状态!!!在这些状态中找最小值才是有效的!!!

最终的代码如下:

//p18 14
//求绝对值
#define MAX_INT 0x7fffffff;

int abs(int a){
    return a > 0 ? a : -a;
}

//a是否为最小值
bool isMin(int a,int b,int c){
    return a <= b && a <= c;
}

int findMinTrip(SqlList &L1,SqlList &L2,SqlList &L3){
    ElemType minTrap = MAX_INT;
    int i = 0,j = 0,k = 0;

    int len1 = L1.length,len2 = L2.length,len3  = L3.length;

    while (i 0)
    {
        int D = abs(L1.data[i] - L2.data[j]) + abs(L1.data[i] - L3.data[k]) + abs(L2.data[j] - L3.data[k]);


        minTrap = minTrap < D ? minTrap : D;

        if(isMin(L1.data[i],L2.data[j],L3.data[k])){
            i++;
        }
        else if(isMin(L2.data[j],L1.data[i],L3.data[k])){
            j++;
        }
        else if(isMin(L3.data[k],L1.data[i],L2.data[j])){
            k++;
        }
    }

    return minTrap;
        

}

你可能感兴趣的:(算法,c++,数据结构,考研)