【问题标题】:how can I make this programme faster? [duplicate]我怎样才能使这个程序更快? [复制]
【发布时间】:2017-11-06 19:36:04
【问题描述】:

任务是编写一个程序,它读入一个整数 k,并打印出正整数的个数 介于 1 和 100000(含)之间,恰好有 k 个除数。例如,数字 24 有 8 个除数: 1、2、3、4、6、8、12 和 24。

我有一个正在运行的程序,但有没有我可以加快搜索速度??

#include <stdio.h>
#include <math.h>


int main(void)
{   int a; //user input//
    int divisors; //running total of number of divisors//
    int sum; //running total of numbers with the required number of divisors//

    printf("Enter the target number of divisors:");
    scanf("%d", &a);
    printf("\n");

    int i;
    for (i=1; i<=100000; i++)
    {
            divisors=2;
            int p;
            for(p=2; p<i; p++)
            {if (i%p==0)
            divisors++;}

        if (divisors==a)  
        sum++;}

    printf("There are %d numbers between 1 and 100000 inclusive which have exactly %d divisors.", sum, a);

return 0;
}

【问题讨论】:

  • 那是经典。仅循环直到 sqrt(i),如果找到一个除数,则添加另一个除数,除非它相同(完美平方的情况)。
  • 每当我执行循环直到 i 的平方根时,每次运行程序时它都会给我一个不正确且不同数量的除数
  • 检查重复链接并接受您的问题是重复的。为了加快速度,您只需要循环直到 int(sqrt(n)) 包括在内,但是如果 n 是一个完美的平方,则有一种特殊情况,在这种情况下,您必须低于 1,因为您计算了平方根两次。
  • @Jean-FrançoisFabre - 链接到答案中的 cmets 包括从未纳入该答案的建议优化。我在下面发布的答案包括这些优化。
  • @Jean-FrançoisFabre - 我在我的答案中添加了第二个类似例子,这与链接到的答案有很大不同。

标签: c


【解决方案1】:

示例代码。移动了 i 和 p 的声明以与旧的 C 类型编译器兼容(我使用的是 Microsoft / Visual Studio)。使用 ceil(sqrt(i)) 外循环。该代码处理输入 1(只有数字 1 有 1 个除数)。输入 2 将输出小于 100,000 的素数个数(有 9592 个小于 100,000 的素数)。

这种方法需要超过 2100 万次迭代。迭代次数 ~= .67 n sqrt(n)。

#include <stdio.h>

int main(void)
{
    int a;          /* user input */
    int divisors;   /* total number of divisors */
    int sum;        /* count of numbers with required number of divisors */
    int i;          /* moved here for C compiler */
    int p;          /* moved here for C compiler */ 
    int sqrti;      /* ceil(sqrt(i)) */

    printf("Enter the target number of divisors: ");
    scanf("%d", &a);
    printf("\n");
    sum = 0;                            /* init sum */
    sqrti = 1;                          /* init sqrti */
    for (i = 1; i <= 100000; i++)
    {
        divisors = 0;                   /* init number of divisors */
        if(sqrti*sqrti < i)             /* update sqrti as needed */
            sqrti += 1;
        for(p = 1; p < sqrti; p++)
            if(i%p == 0)                /* if p is a divisor, count it and i/p */
                divisors += 2;
        if(p*p == i)                    /* if p*p == i, count it */
            divisors += 1;
        if (divisors == a)              /* if i has a divisors, increment sum */
            sum += 1;
    }
    printf("There are %d numbers from 1 to 100000 inclusive which have exactly %d divisors.\n", sum, a);
    return 0;
}

如果可以使用类似于筛选素数的方法的数组,则此方法需要超过 100 万次迭代。迭代次数 ~= n ln(n)。

#include <stdio.h>
#define n 100000
int main(void)
{
int * cnt = (int *)calloc(n+1, sizeof(int));
int d;
    printf("Enter the target number of divisors: ");
    scanf("%d", &d);
    /* time complexity O(n log(n)) */
    {
    int i, j;
        for (i = 1; i <= n; i++) {
            for(j = i; j <= n; j += i) {
                cnt[j]++;
            }
        }
    }
    {
    int i;
    int sum = 0;
        for (i = 1; i <= n; i++)
            sum += (cnt[i] == d) ? 1 : 0;
        printf("excactly %d numbers have %d divisors\n", sum, d); 
    }
    free(cnt);
    return 0;
}

【讨论】:

  • 没有评论的反对票(不是很有帮助),并且在它已经被标记为接受的答案之后。答案显然是在被标记为重复之前提供的,虽然它与之前的问答相似,但并不完全是重复的。
  • 您好,只是想知道您为什么将 sqrti 设置为 1?它肯定不会保留为平方根,或者这甚至有关系吗?
  • @RebeccaMeagher - 您可以将 sqrt(1) 视为 1,因此 sqrti 被初始化为 1。这是部分原因,如果输入为 1,程序将检测到只有 1 有 1除数(使用if(p*p == 1)检查)。正如所评论的,sqrti 是 sqrt(i) 的上限(如果不是精确整数,则向上取整),内部 for 循环条件是 p &lt; sqrti 而不是 p &lt;= sqrti,从而无需在内部检查 p*p == i内部循环,允许在内部循环之后对p*p == i 进行一次检查。
  • @RebeccaMeagher - 继续,除数被初始化为 divisors = 0 而不是 divisors = 2。内循环从p = 1 开始,而不是p = 2,所以第一个内循环对数字1 和i 执行divisors += 2,除非sqrti == 1 没有运行内循环并且只检查p*p == i 完成。
  • 好的,谢谢。那么程序本身是否使用 sqrti 整数计算平方根?抱歉,我只是计算机科学的初学者,发现这部分令人困惑
【解决方案2】:

而不是检查p uptil i 的值,我们可以通过检查直到sqrt(i) 进行优化,而不是将divisors 增加1,而是将其增加2,其中一个数字表示k除以i 和第二为数字i/k

n=1000000;

for (i=1; i<=10000; i++)
    {
            divisors=2;
            int p;
            for(p=2; p<=sqrt(i); p++)
            {
                if (i%p==0)
                {
                    if(p != (i/p)
                        divisors = divisors + 2;
                    else 
                      divisors++;
                }
            }

        if (divisors==a)  
        sum++;
}

【讨论】:

  • 每当我执行循环直到 i 的平方根时,每次运行程序时它都会给我一个不正确且不同数量的除数
  • 由于我们正在为p 小于sqrt(i) 运行循环,我们还需要将除数的数量增加1 以考虑sqrt(i)
  • Nope ..my bad..divisor++ 将给出不正确的输入结果,例如 65。
  • @RebeccaMeagher 我已经编辑了我的答案。你能告诉你得到错误结果的情况吗
  • @AditiRawat - 将if(p != i/p) 替换为if(p*p != i) 会更快。
猜你喜欢
  • 2016-09-18
  • 1970-01-01
  • 2017-12-20
  • 1970-01-01
  • 2020-02-20
  • 1970-01-01
  • 1970-01-01
  • 2014-01-17
  • 2023-03-18
相关资源
最近更新 更多