Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 寻找除数对_C++_Performance_Algorithm - Fatal编程技术网

C++ 寻找除数对

C++ 寻找除数对,c++,performance,algorithm,C++,Performance,Algorithm,我试图解决这个问题,但我不知道如何提高代码的性能。当程序必须处理500000个以上的唯一数字(如描述中所示,最多2000000个)时,就会出现问题。然后花了1-8秒的时间来循环所有这些数字。我使用的测试来自,我使用命令对其进行测试 program.exeresult.out 说明: 给您一个n整数a1,a2。。。一您应该确定这样的有序对(i,j)的数量,即i,j等于(1,…,n),i!=j和ai是aj的除数。 第一行输入包含一个整数n(1好的,我不打算为您编写整个算法,但它肯定可以更快地完成。所

我试图解决这个问题,但我不知道如何提高代码的性能。当程序必须处理500000个以上的唯一数字(如描述中所示,最多2000000个)时,就会出现问题。然后花了1-8秒的时间来循环所有这些数字。我使用的测试来自,我使用命令对其进行测试
program.exeresult.out

说明:
给您一个n整数a1,a2。。。一您应该确定这样的有序对(i,j)的数量,即i,j等于(1,…,n),i!=j和ai是aj的除数。

第一行输入包含一个整数n(1好的,我不打算为您编写整个算法,但它肯定可以更快地完成。所以我想这就是您需要开始的:

所以你已经对列表进行了排序,所以你可以从中做出很多假设。比如最高值。它不会有任何倍数。最高值是最高值除以2

这里还有一个非常有用的事实。倍数的倍数也是倍数。(还在后面?;))。以列表[2 4 12]为例。现在您已经找到(4,12)作为一个多对。如果你现在也找到(2,4),那么你可以推断12也是2的倍数。 因为你只需要数对,你可以为每个数字保留一个数字,它有多少个倍数,当你看到这个数字本身就是一个倍数时,把它加起来。 这意味着最好向后迭代排序列表,并寻找除数

也许可以用这样的方式储存
[(三个2),(两个5),…]
存储一个数字出现的频率。再一次,你不必记录它的id,因为你只需要给它们总的对数。
以这种方式存储列表有助于您,因为所有2的倍数都相同。因此,计算一次,然后乘以。

我预计以下操作比OP的算法(优化)快得多:

  • (如果您的语言不支持,则值和频率的类型应为32位无符号、计数64位–在计算计数之前升级。)
  • 读取值的数目,N
  • 读取每个值v,将一个值添加到其频率[v](无需存储)。
    • (freq[MAX](或MAX+1)可以静态分配,以便对所有0进行可能的最佳初始化)
  • 从freq[1]计算涉及1的对的数量和值的数量
  • 对于2..MAX中的每个i(频率[i]>0):
    • 从freq[i]计算成对数(i,i)
    • 对于2m中i的每多米..最大值:
      • (使用m作为循环计数器并递增,而不是相乘)
      • 根据freq[i]和freq[m]计算对数(i,m)
    • (如果freq[i]=1,可以省略(i,i)计算,并执行针对freq[i]=1优化的循环变量)
  • (可以从2..MAX/2执行上一个(外部)循环,然后从MAX/2+1..MAX执行上一个(外部)循环,忽略倍数处理)
对的数目(i,i)=freq[i]C2=(freq[i]*(freq[i]-1))/2。
对的数目(i,j)=freq[i]*freq[j]≠ j

这样可以避免排序、
sqrt
和除法

其他优化 可以存储不同的值,然后扫描该数组(顺序无关紧要);由此产生的增益或损耗取决于1..MAX中值的密度

如果最大频率<216(听起来很有可能),则所有产品都适合32位。我们可以利用这一点,将数字类型作为模板编写函数,跟踪最大频率,然后为其余部分选择适当的模板实例。这将消耗N*(比较+分支),并且可以通过使用32位而不是64位执行D2乘法来获得,其中D是不同值的数目。我看不出有什么简单的方法可以推断,除了N<216之外,32位就足够了

如果对n个处理器进行并行化,可以让不同的处理器处理模为n的不同剩余


我考虑跟踪偶数值的数量,以避免扫描一半的频率,但我认为对于给定参数内的大多数数据集,这不会产生什么优势。

请在问题中包括相关信息,即,请添加练习本身,这样人们就可以知道代码是关于什么的,而不必访问将来可能会被破坏的链接。这将更适合那里,根本不需要对它们进行排序,只需这样做:
for i=1..n;对于j=i+1..n;如果j | i或i | j;计数+++
。需要
O(n^2/2)=O(n^2)
工作。我怀疑你能更快地完成它,我真的看不出预排序的好处(当然我可能错了)。@Synchro你试过了吗。人们努力工作,尽可能地优化它,而且它没有bug。为什么要重新发明轮子?这对你来说慢了吗?@Synchro或者更好,你的
countVect
已经在做计数排序的第一阶段了,做第二阶段来生成排序列表很简单。你读过他的代码了吗?答案的最后一部分已经在他的代码中完成了。第一部分不清楚如何将其翻译成代码。哎呀,我没听清楚,但我想我现在就去写一些代码;)@Synchro:我知道你已经接受了,但我应该指出一个重要的更正:我最初说的所有类型都是32位的,这当然是错误的,我已经更正了。是的,但是你关于乘法值的想法是正确的,并且足够好,可以通过后续测试。微观优化在这里并不重要。这并不难,但这类任务需要程序员以不同的方式思考。上面的代码不是我算法的第一个版本。第一个很慢,但是
#include <iostream>
#include <math.h>
#include <algorithm>

#include <time.h>


#define COUNT_SAME(count) (count - 1) * count


int main(int argc, char **argv) {
    std::ios_base::sync_with_stdio(0);

    int n; // Total numbers
    scanf("%d", &n);

    clock_t start, finish;
    double  duration;

    int maxVal = 0;
    long long *countVect = new long long[2000001]; // 1-2,000,000; Here I'm counting duplicates

    unsigned long long counter = 0;
    unsigned long long operations = 0;

    int tmp;
    int duplicates = 0;

    for (int i = 0; i < n; i++) {
        scanf("%d", &tmp);

        if (countVect[tmp] > 0) { // Not best way, but works
            ++countVect[tmp];
            ++duplicates;
        } else {
            if (maxVal < tmp)
                maxVal = tmp;

            countVect[tmp] = 1;
        }
    }

    start = clock();

    int j;
    int jCounter = 1;

    for (int i = 0; i <= maxVal; ++i) {
        if (countVect[i] > 0) { // Not all fields are setted up
            if (countVect[i] > 1)
                counter += COUNT_SAME(countVect[i]); // Sum same values

            j = i * ++jCounter;

            while (j <= maxVal) {
                if (countVect[j] > 0)
                    counter += countVect[i] * countVect[j];

                j = i * ++jCounter;
                ++operations;
            }

            jCounter = 1;
        }
    }

    finish = clock();
    duration = (double)(finish - start) / CLOCKS_PER_SEC;
    printf("Loops time: %2.3f", duration);
    std::cout << "s\n";
    std::cout << "\n\nCounter: " << counter << "\n";
    std::cout << "Total operations: " << operations;

    std::cout << "\nDuplicates: " << duplicates << "/" << n;
    return 0;
}