繁体   English   中英

使线性搜索更高效

[英]Making linear search more efficient

我有 3 个灯泡的问题,它们以不同的速率打开,并被告知找到并计算它们同时打开的时间(基于给定的时间范围)。 示例:1 2 3 1 20(1 是开始时间,20 是结束时间)将是 output 36. (6 + 12 + 18)。 下面的代码有效,但它可能会更快。 我怎样才能做得更好? 谢谢你的帮忙。

long long int total = 0, time1 = 0, time2 = 0, time3 = 0, start = 0, end = 0;

        scanf("%lli %lli %lli %lli %lli", &time1, &time2, &time3, &start, &end);
        
        for(int j = start; j <= end; j++)
        {  
            if(j % time1 == 0 && j % time2 == 0 && j % time3 == 0)
            {
                total = total + j;
            }
        }
        printf("Case #%i: %lli\n", testcase, total);

与许多算法问题一样,有一个数学观察可以大大加快您的代码速度。 对于要被所有 3 个灯泡整除的时间,时间必须能被它们的最小公倍数整除。 因此,您会得到一个必须在开始和结束之间检查的固定时间间隔。 这也可以用另一个公式来完成。

该问题可以分解为以下步骤:

  1. 找到最小公倍数,打开时间的LCM
  2. 通过将开始向上舍入为LCM的倍数以获得第一个,并通过向下舍入为LCM的倍数获得最后一个,找到所需范围 [ start , end ] 内LCM倍数的第一次最后一次出现。
  3. 求 [ first , last ] 范围内LCM的倍数, N = (( last - first ) / LCM ) + 1。
  4. 将[ first , last ]范围内的LCM的倍数求和,用等差数列求和公式求和, sum = ( N * ( first + last )) / 2。

导通时间的最小公倍数 LCM可以通过首先找到导通时间的最大公约数GCD和导通时间的乘积P来找到,然后LCM = P / GCD 著名的欧几里德算法可以用来求一对数的最大公约数,并且可以多次使用该算法来确定整体的最大公约数。

以上步骤由下面的function get_total实现。

unsigned long long int gcd(unsigned long long int a, unsigned long long int b)
{
    while (b) {
        unsigned long long int t = b;
        b = a % b;
        a = t;
    }
    return a;
}

unsigned long long int
get_total(unsigned long long int start, unsigned long long int end,
        unsigned int ntimes, const unsigned long long int *times)
{
    unsigned long long int g;   /* GCD of times */
    unsigned long long int l;   /* LCM of times */
    unsigned long long int first, last;
    unsigned long long int n;
    unsigned long long int total;

    if (ntimes == 0 || times[0] == 0)
        return 0;   /* error */

    /* Calculate GCD and LCM of times. */
    g = times[0];
    l = 1;
    for (unsigned int i = 1; i < ntimes; i++) {
        if (times[i] == 0)
            return 0;   /* error */
        g = gcd(times[i], g);
        l *= times[i];
    }
    l *= times[0] / g;
    /* Get the first and last occurrences of multiples of LCM in range. */
    first = ((start + (l - 1)) / l) * l;    /* round up */
    last = end - (end % l);                 /* round down */
    if (first > last)
        return 0;
    /* Get number of occurrences of multiples of LCM in range. */
    n = ((last - first) / l) + 1;
    /* Get sum of arithmetic progression of multiples of LCM in range. */
    total = (n * (first + last)) / 2;
    return total;
}

ntimes是times指向的数组中灯泡点亮的times

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM