试商法 素数探求 c语言,连续合数探求

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

最多连续合数区间中不能存在素数,最小连续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

#include

int main()

{

long c,d,i,j,f,t,f1,i1,max;

printf("请输入c,d(2

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

最多连续合数的个数为: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

#include

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

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

最多连续合数的个数为: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

#include

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]所有的时间就比较长;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值