题目描述:
输入两个整数X和Y,输出两者->>之间<<-的素数个数(包括X和Y)。
Input:
两个整数X和Y(1 <= X,Y <= 105)。
Output:
输出一个整数,表示X,Y之间的素数个数(包括X和Y)。
Sample Input:
1 100
Sample Output:
25
我的代码1:
#include <stdio.h>
int Isprime(int x){
int i;
for(i=2;i<x;i++){
if(x%i==0) break;
}
if(i==x) return 1;
return 0;
}
int main()
{
int X,Y,i;
int s=0;
scanf("%d %d",&X,&Y);
for(i=X;i<=Y;i++){
if(Isprime(i)) s++;
}
printf("%d\n",s);
return 0;
}
错误点1:题目只描述了A和B分别的范围,但是并没有说明A和B谁大谁小,所以我们得做个简单的交换。
错误点2:我写的代码用到了两个for循环,运行时间超过了题目限制。
于是我用到了倍数筛选法,先定义一个容量为100010的数组,多出10是为了防止鲁棒性(即程序在运行较复杂的问题出现的多占用内存问题,防止报错),从2开始遍历,到Y结束,将具有倍数关系的数字筛选出去,剩下的除了1就是素数了。
代码2:
#include <stdio.h>
int main()
{
int Notprime[100010];
int X,Y,t;
int a=0;
scanf("%d %d",&X,&Y);
if(X>Y){
t=X;
X=Y;
Y=t;
}
int i,j;
for(i=2;i<=Y;i++){
for(j=2*i;j<=Y;j+=i){
Notprime[j]=1;
}
}
for(i=X;i<=Y;i++){
if(Notprime[i]==0&&i!=1) a++;
}
printf("%d\n",a);
return 0;
}
运行结果:
但尽管如此,还是不满足题目条件,运行效率还是不够。
这里我们得接触到更高效率的素数筛法。
就代码2来看,当i=2的时候j能取到6,当i=3的时候,j同样重复取到了6,于是纵观数据100000,这其中得重复遍历多少次啊。所以我们得加以条件限制if(Notprime[j]==0)再进行遍历。说实话,这样写就已经符合题目限制了。
代码3:
#include <stdio.h>
int main()
{
int Notprime[100010];
int X,Y,t;
int a=0;
scanf("%d %d",&X,&Y);
if(X>Y){
t=X;
X=Y;
Y=t;
}
int i,j;
for(i=2;i<=Y;i++){
if(Notprime[i]==0){
for(j=2*i;j<=Y;j+=i){
Notprime[j]=1;
}
}
}
for(i=X;i<=Y;i++){
if(Notprime[i]!=1&&i!=1) a++;
}
printf("%d\n",a);
return 0;
}
但是遍历条件从j=2*i改成j=i*i,程序又得到了进一步的优化。带入一些数据不难发现,j=i*i将数据都覆盖了,而且重复率大大降低。
#include <stdio.h>
int main()
{
int Notprime[100010];
int X,Y,t;
int a=0;
scanf("%d %d",&X,&Y);
if(X>Y){
t=X;
X=Y;
Y=t;
}
int i,j;
for(i=2;i<=Y;i++){
if(Notprime[i]==0){
for(j=i*i;j<=Y;j+=i){
Notprime[j]=1;
}
}
}
for(i=X;i<=Y;i++){
if(Notprime[i]!=1&&i!=1) a++;
}
printf("%d\n",a);
return 0;
}
如果用函数写,可以这样
代码:
#include <stdio.h>
#include <math.h>
int prime(int x){
int k;
if(x==1) return 0;
k=(int)sqrt(x);
for(int i=2;i<=k;i++){
if(x%i==0) return 0;
}
return 1;
}
int main()
{
int n,m,i;
scanf("%d %d",&m,&n);
for(i=m;i<=n;i++){
if(prime(i)==1) printf("%d ",i);
}
printf("\n");
return 0;
}