我必须在两个限制n
和m
,t
之间打印数字。
我创建了t
变量,以及两个指针n, m
,指向t
整数值的保留内存块。
我使用指针而不是数组来做更快的操作。
外for
循环针对每个测试用例进行迭代,并增加m
和n
指针。
内部for
循环打印从m[i]
到n[i]
的素数。
#include <stdio.h>
#include <stdlib.h>
int is_prime(int);
int main(void) {
int t;
int *n = malloc(sizeof(int) * t);
int *m = malloc(sizeof(int) * t);
scanf("%d", &t);
for (int i = 0; i < t; i++, m++, n++) {
scanf("%d %d", &m[i], &n[i]);
for (int j = m[i]; j <= n[i]; j++) {
if (is_prime(j)) {
printf("%d\n", j);
}
}
if (i < t - 1) printf("\n");
}
return 0;
}
int is_prime(int num)
{
if (num <= 1) return 0;
if (num % 2 == 0 && num > 2) return 0;
for(int i = 3; i < num / 2; i+= 2){
if (num % i == 0)
return 0;
}
return 1;
}
问题:http://www.spoj.com/problems/PRIME1/
代码正在http://ideone.com上正确编译,但当我尝试在SPOJ上提交此代码时,我给出了“超出时间限制”错误。如何减少此素数生成器的执行时间?
答案 0 :(得分:2)
正如@Carcigenicate建议的那样,你超过了时间限制因为你的素数发生器太慢了;由于您使用效率低下的算法,因此速度太慢。
实际上,你不应该简单地测试每个连续数字的素数(顺便说一句,你也做无效),而是使用已知的素数(也许是你的其他素数)一次排除多个值计算)。例如,您不需要检查素数的5和10的倍数(除了实际值5),因为您知道5除以它们。所以只是&#34;标记&#34;各种素数的倍数是不相关的。
...当然,这只是为了让你开始,你可以使用各种技巧进行优化 - 算法和实现相关。
答案 1 :(得分:0)
我知道您正在寻找算法改进,但以下技术优化可能有所帮助:
如果您使用的是Visual Studio,则可以使用alloca而不是malloc,以便n和m进入堆栈而不是堆。
您也可以尝试使用数组而不是指针来重写算法,以便将n和m放入堆栈中。
如果你想继续使用指针,请在星号后面使用__restrict关键字,这会提醒编译器你没有引用这两个指针。
答案 2 :(得分:0)
有几种方法可以改进整数n
的素数检查。以下是您可能会觉得有用的一些内容。
减少支票数量:一个众所周知的定理是,如果您想查找n
的因素,请说n = a * b
,那么你可以在1
和sqrt(n)
之间寻找除数。 (证明很容易,主要的论点是我们有三个案例,a = b = sqrt(n)
,或者我们有a < sqrt(n) < b
或b < sqrt(n) < a
。而且,无论我们遇到什么情况,都会有n
与1
之间的因子sqrt(n)
。
使用Eratosthenes筛选:这种方式可以丢弃以前被取消资格的不必要的候选人(参见Sieve of Eratosthenes(维基百科))
使用概率算法:现在检查素数的最有效方法是使用概率测试。实现起来有点复杂,但效率更高。您可以找到一些这些技术here(维基百科)。
答案 3 :(得分:0)
您甚至可以在不使用指针或数组的情况下执行此操作
#include <stdio.h>
#include<math.h>
int is_prime(long n){
if (n == 1 || n % 2 == 0)
return 0;
if (n == 2)
return 1;
for (long i = 3; i <= sqrt(n); i += 2) {
if(n % i == 0)
return 0;
}
return 1;
}
int main() {
int t;
scanf("%d",&t);
while(t--) {
long n, m;
scanf("%ld %ld",&n,&m);
for (long i = n; i <= m; i++) {
if (is_prime(i) == 1)
printf("%ld\n",i);
}
}
return 0;
}