连续合数探求

来源:互联网 发布:泳衣淘宝网 编辑:程序博客网 时间:2024/06/06 07:00

本节探讨连续合数问题,实际上还是与素数密切相关;

最多连续合数区间中不能存在素数,最小连续n个合数中也不能存在素数;


最多连续合数区间

试在指定区间 [c,d] 内探求最多连续合数的个数及最多连续合数的起始与终止数;

例如输入c,d:10,100,在区间[10,100]内最多连续合数的个数为7个,所求得的连续合数区间为:[90,96];

下面应用试商法筛法两种设计分别求解;

应用试商设计:

1.说明:

对指定区间[c,d]内的每一个奇数i应用试商法判别是否为素数,若i(t=0)为素数,则i-f(f为i前面的素数)与max比较以求取最多并用变量f1和i1记录;

随后,f=i即把素数i赋值给f,为下一个素数进行比较做准备;

最多连续合数的起始数f+1有可能与区间起始数c重合,因而当c为偶数或非素数时有必要作赋值:f=c-1

注意:以上比较所得max不是f与i之间的合数个数,max比f与i之间的合数个数多了1;

2.程序设计:

#include<stdio.h>#include<math.h>int main(){   long c,d,i,j,f,t,f1,i1,max;   printf("请输入c,d(2<c<d):");   scanf("%ld,%ld",&c,&d);   f=c;   max=0;   if(c%2!=0)   {      for(t=0,j=3;j<=sqrt(c);j+=2) /*试商判别下限c是否为素数*/         if(c%j==0)         {            t=1;            break;         }   }   if(c%2==0||t==1)   /*令c-1为素数并赋值给f*/      f=c-1;   if(c%2==0)      c++;   for(i=c;i<=d;i+=2)   {      t=0;      for(j=3;j<=sqrt(i);j+=2)  /*试商判别素数*/         if(i%j==0)         {            t=1;            break;         }      if(d-i<2 && t==1)      {         t=0;         i=d+1;  /*令d+1为素数并赋值给i*/      }      if(t==0)   /*t为0表明i为素数*/      {         if(i-f>max)         {            max=i-f;            f1=f+1;            i1=i-1;         }         f=i;    /*f为i的前一个素数*/      }   }   printf("最多连续合数的个数为:%ld\n",max-1);   printf("连续合数区间为:[%ld,%ld]\n",f1,i1);}

3.程序运行示例:

请输入c,d(2<c<d):10000,1000000最多连续合数的个数为:113连续合数区间为:[492114,492226]
应用筛法:

求出区间 [c,d] 内的所有相邻素数对f,m,求取m-f的最大值max;

注意到本题的搜索范围较大,采用效率较高的筛法求素数是适宜的;

1.说明:

应用筛法求素数,为了方便实施“划去”操作,设置数组;

考虑到有时待测区间[c,d]比较大,为不使数组下标超维,把[c,d]分割为若干个子区间[cs,ds],确保在子区间中操作不超维;

每一数组元素对应一个待判断的奇数,并赋初值0,如果该奇数为p的倍数则应划去,对应元素加一个划去标记,通常给该元素赋值-1,最后,打印元素值不是-1(即没有划去)的元素对应的奇数即所求素数;

在实际应用筛法的过程中,p通常不限于取不超过sqrt(x)的素数,而是适当放宽取不超过sqrt(x)的奇数(从3开始),这样做尽管多了一些重复划去操作,但程序实现要简便些;

在指定区间[cs,ds](约定cs为奇数)上所有奇数表示为j=cs+2k(k=0,1,……,e,这里e=(ds-cs)/2),于是k=(j-cs)/2是奇数j在数组中的序号(下标),如果j为奇数的倍数时,对应数组元素作划去标记,即a[(j-cs)/2]=-1;

根据cs与奇数i确定g=2*int(cs/(2 * i))+1,使得gi接近区间下限cs,从而使划去的gi,(g+2) * i,……在[cs,ds]中,减少无效操作,以提高对大区间的筛选效率;

最后,凡数组元素a[k]!=-1,对应的奇数j=cs+2k就为素数;

2.程序设计:

#include<stdio.h>#include<math.h>int main(){   long c,d,cs,ds,ct,dt,f,g,i,j,k,m,max,a[11000];   int e,u,x,y;   printf("请输入c,d(2<c<d):");   scanf("%ld,%ld",&c,&d);   if(d-c<=20000)   {      cs=c;      ds=d;      x=0;   }   else   {      x=(d-c)/20000;      cs=c;      ds=d-20000*x;   }   f=cs;   max=0;   for(y=1;y<=x+1;y++)  /*把[c,d]分x+1个子区间筛选素数*/   {      if(cs%2==0)         cs++;      for(i=0;i<=10999;i++)         a[i]=0;      e=(ds-cs)/2;      i=1;      while(i<=sqrt(ds))      {         i=i+2;         g=2*(cs/(2*i))+1;         if(g*i>ds)            continue;         if(g==1)            g=3;         j=i*g;         while(j<=ds)         {            if(j>=cs)  /*赋值筛去标记-1*/               a[(j-cs)/2]=-1;            j=j+2*i;         }      }      for(u=1,k=0;k<=e;k++)      {         if(a[k]!=-1)         {            m=cs+2*k;   /*m即筛选所得素数*/            if(m-f>max)  /*寻求两相邻素数间距的最大值*/            {               max=m-f;               ct=f+1;               dt=cs+2*k-1;            }            f=m;         }      }      cs=ds+1;      ds=ds+20000;  /*cs与ds增长后继续探求*/   }   printf("最多连续合数的个数为:%ld\n",max-1);   printf("连续合数区间为:[%ld,%ld]\n",ct,dt);}

3.程序运行示例及其注意事项:

请输入c,d(2<c<d):10,10000000最多连续合数的个数为:153连续合数区间为:[4652354,4652506]

注意:如果测试的区间比较大,应用筛法所需时间比试商判别要短,有兴趣的读者不妨用实例进行比较


最小连续n个合数

试求出最小的连续n个合数(其中n是键盘输入的任意正整数);

例如输入n=7,最小的连续7个合数为 [90,96];

1.说明:

求出区间 [c,d] 内的所有素数(区间起始数c可由小到大递增),检验其中每相邻两素数之差,若某相邻的两素数m和f之差大于n,即m-f>n,则区间[f+1,f+n]中的n个数为最小的连续n个合数;

应用试商法求指定区间[c,d](约定起始数 c=3,d=c+10000)上的所有素数,求出该区间内的一个素数m,设前一个素数为f,判别:若m-f>n,则输出结果[f+1,f+n]后结束;否则,作赋值f=m,为求下一个素数做准备

如果在区间[c,d]中没有满足条件的解,则作赋值:c=d+2,d=c+10000,继续试商下去,直到找出所要求的解;

2.程序设计:

#include<stdio.h>#include<math.h>int main(){   long c,d,f,m,j;   int t,n;   printf("求最小的n个连续合数。\n");   printf("请输入n(n<200):");   scanf("%d",&n);   c=3;   d=c+10000;   f=3;   while(1)   {      for(m=c;m<=d;m+=2)      {         for(t=0,j=3;j<=sqrt(m);j+=2)            if(m%j==0)   /*实施试商*/            {               t=1;               break;            }         if(t==0 && m-f>n)  /*满足条件进行输出*/         {            printf("最小的%d个连续合数区间为:",n);            printf("[%ld,%ld]  \n",f+1,f+n);            return;         }         if(t==0)  /*每求出一个素数m后赋值给f*/            f=m;      }      if(m>d)      {                 c=d+2;      /*每一轮试商后改变c和d转下一轮*/         d=c+10000;      }   }}

3.程序运行示例及其注意事项:

求最小的n个连续合数。请输入n(n<200):100最小的100个连续合数区间为:[370262,370361]。

注意:随着n的增加,最小的n个连续合数也随之迅速变大,搜索也随之变得困难,例如输入n=200,搜索最小的200个连续合数区间[20831324,20831523]所有的时间就比较长

1 0
原创粉丝点击