• 沒有找到結果。

趣味C程序设计集锦 - 万水书苑-出版资源网

N/A
N/A
Protected

Academic year: 2021

Share "趣味C程序设计集锦 - 万水书苑-出版资源网"

Copied!
21
0
0

加載中.... (立即查看全文)

全文

(1)三、素数——上帝用来描写宇宙的文字. 14 素数 1.问题提出 素数是上帝用来描写宇宙的文字(伽俐略语) 。 素数 ,又称为质 数,是不能 被 1 与本 身以外的其他整 数整除的整 数。如 2,3,5,7,11,13,17 是前几个素数,其中 2 为唯一的偶素数。 与此相对应,一个整数如果能被除 1 与本身以外的整数整除,该整数称为合数或复 合数。例如,15 能被除 1 与 15 以外的整数 3、5 整除,15 是一个合数。 特别地,数 1 既不是素数,也不是合数。 作为一类特殊的整数,素数是数论中探讨最多也是难度最大的一类整数,其中有些 问题是著名数学家提出并研究过的经典趣题。 求素数的常用方法有试商判别法和筛法两种。试求出指定区间上的所有素数,并统 计该区间上素数的个数。 2.试商判别法求素数 (1)设计要点 试商判别法是依据素数的定义来实施的。应用试商法来探求奇数 i(只有唯一偶素 数 2,不作试商判别)是不是素数,用奇数 j(取 3,5,…,直至 sqrt(i))去试商。 若存在某个 j 能整除 i,说明 i 能被 1 与 i 本身以外的整数 j整除,i 不是素数。若上 述范围内的所有奇数 j 都不能整除 i,则 i 为素数。 有些程序把试商奇数 j 的取值上限定为 i/2 或 i-1 也是可行的,但并不是可取的, 这样无疑会增加了试商的无效循环。理论上说,如果 i 存在一个大于 sqrt(i)且小于 i 的因数,则必存在一个与之对应的小于 sqrt(i)且大于 1 的因数,因而从判别功能来说, 取到 sqrt(i)已足够了。 判别 j 整除 i,常用表达式 i%j=0 实现。 (2)应用试商法求区间素数程序设计 /* 试商法求指定区间上素数 c141 */ #include <stdio.h>.

(2) 三、素数——上帝用来描写宇宙的文字. Chapter 3. #include <math.h> void main() { long c,d,i,j; int t,n=0; printf(" 求区间[c,d]上的素数\n"); printf(" 请输入 c,d(c>2):"); scanf("%ld,%ld",&c,&d); if(c%2==0) c=c+1; for(i=c;i<=d;i+=2) { for(t=0,j=3;j<=sqrt(i);j+=2) if(i%j==0) /* 实施试商 */ {t=1;break;} if(t==0) /* 标志量 t=0 时 i 为素数 */ { printf("%9ld",i); n++; if(n%10==0) printf("\n"); } } printf("\n 共%d 个素数.",n); }. (3)程序运行示例 求区间[c,d]上的素数。 请输入 c,d(c>2):2000,2100 2003 2011 2017 2027 2029 2039 2053 2063 2069 2081 2083 2087 2089 2099 共 14 个素数. 3.筛法求素数 (1)筛法简介 求素数的筛法是公元前三世纪的厄拉多塞(Eratosthenes)提出来的:对于一个大 整数 x,只要知道不超过 sqrt(x)的所有素数 p,划去所有 p 的倍数 2p,3p,...,剩下 的整数就是不超过 x 的全部素数。 应用筛法求素数,为了方便实施“划去”操作,应设置数组。每一数组元素对应 一个待判别的奇数,并赋初值 0。如果该奇数为 p 的倍数则应划去,对应元素加一个划 去标记,通常给该元素赋值-1。最后,打印元素值不是-1(即没有划去)的元素对应的. 43.

(3) 趣味 C 程序设计. 奇数即所求素数。 Chapter 3. 在实际应用筛法的过程中,p 通常不限于取不超过 sqrt(x)的素数,而是适当放宽 取不超过 sqrt(x)的奇数(从 3 开始) 。这样做尽管多了一些重复划去操作,但程序实现 要简便些。 (2)应用筛法求素数设计要点 在指定区间[c,d](约定 c 为奇数)上所有奇数表示为 j=c+2k(k=0,1,...,e, 这里 e=(d-c)/2)。于是 k=(j-c)/2 是奇数 j 在数组中的序号(下标) 。如果 j 为奇数的 倍数时,对应数组元素作划去标记,即 a[(j-c)/2]=-1。 根据 c 与奇数 i,确定 g=2*int(c/(2*i))+1,使得 gi 接近区间下限 c,从而使划 去的 gi,(g+2)i,...在[c,d]中,减少无效操作,以提高对大区间的筛选效率。 最后,凡数组元素 a[k]≠-1,对应的奇数 j=c+2k 则为素数。 (3)筛法求素数程序实现 /* 筛法求指定区间上的素数 c142 */ #include <stdio.h> #include <math.h> void main() { long int c,d,g,i,j,k; int e,n; static long int a[11000]; printf("求区间[c,d]上的素数。\n"); printf("请输入 c,d(c>2):"); scanf("%ld,%ld",&c,&d); if (c%2==0) c++; e=(d-c)/2;i=1; while (i<=sqrt(d)) /* 在[c,d]中筛选素数 */ { i=i+2;g=2*(c/(2*i))+1; if(g*i>d) continue; if(g==1) g=3; j=i*g; while (j<=d) { if(j>=c) a[(j-c)/2]=-1; /* 筛去标记-1 */ j=j+2*i; } } for(n=0,k=0;k<=e;k++) if(a[k]!=-1) /* 输出所得素数 */ {. 44.

(4) 三、素数——上帝用来描写宇宙的文字. Chapter 3. n++; printf("%ld ",c+2*k); if(n%10==0) printf("\n"); } printf("\n 共%d 个素数。\n",n); }. (4)程序运行示例与说明 求区间[c,d]上的素数。 请输入 c,d(c>2):1671800,1672000 1671907 1671941 1671947 1671961 1671977 1671983 1671997 共 7 个素数。 求素数的两个方法比较,各有所长。试商法较为直观,设计容易实现,因此常为程 序设计爱好者所采用。筛法在较大整数的判别上效率更高一些,但设计上较难把握。. 15 乌兰现象 1.问题提出 美国著名数学家乌兰教授(S.Ulam)有一次参加一个科学报告会,为了消磨时间, 他在一张纸上把 1,2,3,…,100 按反时针的方式排成一种螺旋形式,并标出全部素 数。他突然发现这些素数大都扎堆于一些斜线上。散会后,他在计算机上把 1~65000 这些整数排成反时针螺旋式,并打印出来。他发现这些素数仍然具有挤成一条直线的特 性。这种现象在数学上称为“乌兰现象” 。 后来,数学家从“乌兰现象”中找到了素数的许多有趣性质。 设计程序,把整数序列 1,2,3,4,…排列成方螺线数阵,1 置放在中心位置,以 后各整数依次按逆时针方螺线位置排列。为清楚显示,设计用另一种颜色标注所有素数。 2.设计要点 数字方螺线是从正中间开始的。随整数 n 的增加,位置呈逆时针方螺线展开。 设整数 n 所在的坐标(x,y)为(x(n),y(n))。 在第 i 圈分 4 步操作(分别在条件循环中实施) : 向上增长,n 每增 1,x(n)不变,y(n)增 1,直至 y(n)=i 时转向。 向左增长,n 每增 1,y(n)不变,x(n)减 1,直至 x(n)=-i 时转向。 向下增长,n 每增 1,x(n)不变,y(n)减 1,直至 y(n)=-i 时转向。 向右增长,n 每增 1,y(n)不变,x(n)增 1,直至 x(n)=i 时转下一圈。. 45.

(5) 趣味 C 程序设计. 设置 k 循环,k=1,2,3,…,m*m,在循环中应用试商判别 k 是否为素数(若为素 Chapter 3. 数标记 r=0) 。输出时应用 c 语言的格式输出语句: gotoxy(x,y);. /* 将光标移至指定(x,y)位置 */. cprintf("%3d",k); /* 将格式化输出送到当前窗口 */ 显示输出时,用区别一般整数的另一种颜色标注所有素数。 3.乌兰现象程序设计 /* 乌兰现象再现 c151 */ #include "stdio.h" #include "conio.h" #include "math.h" void main(void) { int i,j,k,t,m,n,r,x[1000],y[1000]; printf(" 请输入数阵的阶数 m:"); scanf("%d",&m); x[1]=0; y[1]=0; n=1; t=m/2; for(i=1;i<=t;i++) { n=n+1; x[n]=x[n-1]+1; y[n]=y[n-1]; while(y[n]<i) /* 分情况计算 n 所在的坐标 */ { n=n+1; x[n]=x[n-1]; y[n]=y[n-1]+1; } while(x[n]>-i) { n=n+1; x[n]=x[n-1]-1; y[n]=y[n-1]; } if(i==t && m%2==0) /* m 为偶数时少半圈 */ break; while(y[n]>-i) { n=n+1; x[n]=x[n-1];y[n]=y[n-1]-1; } while(x[n]<i). 46.

(6) 三、素数——上帝用来描写宇宙的文字. {. } } printf(" 所求%d 阶数字方螺线为:\n",m); for(k=1;k<=m*m;k++) { for(r=0,j=2;j<=sqrt(k);j++) if(k%j==0) /* 检验 k 是否为素数 */ {r=1;break;} if(r==0 && k!=1) { textbackground(5); /* 素数用另一颜色打印 */ gotoxy(50+x[k]*4,15-y[k]*2); cprintf("%3d",k); } else { textbackground(0); gotoxy(50+x[k]*4,15-y[k]*2); cprintf("%3d",k); } }. Chapter 3. n=n+1; x[n]=x[n-1]+1; y[n]=y[n-1];. }. 4.程序运行示例 运行程序,所得乌兰现象如图 15-1 所示。. 图 15-1 素数扎堆乌兰现象图. 我们可以看到图中素数沿斜线扎堆的乌兰现象。在这些“素数斜线”上,也有 39、. 47.

(7) 趣味 C 程序设计. 15、33、93、85、65 等非素数,分别为两个素数之积,都比较“接近素数” 。 Chapter 3. 从图上还可看到,奇数的平方数在半条斜线上,而偶数的平方数在另半条斜线上。 注意:程序应在 TC 环境下运行,VC 环境下对库函数 textbackground()和 gotoxy() 不解释。. 16 孪生素数 1.问题提出 相差为 2 的两个素数称为孪生素数。例如,3 与 5 是一对孪生素数,41 与 43 也是 一对孪生素数。 试求出指定区间上的所有孪生素数对。 2.常规求解 (1)求解要点 设置两个变量:当前素数变量 i 与相邻的前一个素数变量 f。在求出当前素数 i 后, 求 i 与它相邻的前一个素数 f 的差。如果 i-f=2 则 f,i 为所求的一对孪生素数。 每求出一个素数 i 并作判断后,要注意把该素数 i 存储到 f,为继续寻求孪生素数 对作准备。 (2)程序实现 /* 求指定区间上的孪生素数对 c161 */ #include <stdio.h> #include <math.h> void main() { long int c,d,i,j,f=0; int t,n=0; printf("求区间[c,d]上的孪生素数对\n"); printf("请输入 c,d(c>2):"); scanf("%ld,%ld",&c,&d); if (c%2==0) c++; /* 确保起点 c 为奇数 */ for(i=c;i<=d;i+=2) { for(t=0,j=3;j<=sqrt(i);j+=2) /* 试商判别素数 */ if(i%j==0) {t=1;break;} if(t==0) /* t 为 0 表明 i 为素数 */ {. 48.

(8) 三、素数——上帝用来描写宇宙的文字. Chapter 3. if(i-f==2) { printf("(%ld,%ld)",f,i); n++; } f=i; /* 素数 i 存储到 f,为后一差别作准备 */ } } printf("\n[%ld,%ld]上共%d 对孪生素数。\n",c,d,n); }. (3)程序运行示例。 运行程序,输入区间 101,200,得 (101,103) (107,109) (137,139) (149,151) (179,181) (191,193) (197,199) [101,200]上共 7 对孪生素数。 3.设置数组求解 (1)求解要点 求出指定区间内的所有素数并依次存储到一个数组。数组中相邻元素之差若为 2, 这两个素数相差为 2,即为一对孪生素数。 (2)程序实现 /* 应用数组求指定区间上的孪生素数对 c162 */ #include <stdio.h> #include <math.h> void main() { long int c,d,i,j; int t,m,n=0; static long int a[5000]; printf("求区间[c,d]上的孪生素数对\n"); printf("请输入 c,d(c>2):"); scanf("%ld,%ld",&c,&d); if (c%2==0) c++; /* 确保起点 c 为奇数 */ for(m=0,i=c;i<=d;i+=2) { for(t=0,j=3;j<=sqrt(i);j+=2) /* 试商法判别素数 */ if(i%j==0) {t=1;break;} if(t==0) a[++m]=i; /* i 为素数给 a 数组赋值 */. 49.

(9) 趣味 C 程序设计. Chapter 3. } for(i=1;i<m;i++) if(a[i+1]-a[i]==2) /* 相邻素数相差为 2 即输出 */ { printf("(%ld,%ld) ",a[i],a[i+1]); n++; } printf("\n[%ld,%ld]上共%d 对孪生素数对。\n",c,d,n); }. (3)程序运行示例 运行程序,输入区间[2000,2100],得 (2027,2029) (2081,2083) (2087,2089) [2001,2100]上共 3 对孪生素数对。. 17 梅森尼数 1.问题提出 形如 2n  1的素数称为梅森尼数(Mersenne Prime) 。例如 22  1  3 、23  1  7 都是梅森尼数。1722 年,双目失明的瑞士数学大师欧拉证明了 231  1 =2147483647 是 一个素数,堪称当时世界上“已知最大素数”的第一个纪录。 试求出指数 n<50 的所有梅森尼数。 2.设计要点 设置指数 n 循环(2~50),循环体中通过累乘 t=t*2,得 t=2^n。 根据梅森尼数的构造形式,对 m=t-1 应用试商法实施素数判别。若 m 为素数,即为 所寻求的梅森尼数,作打印输出。 3.求梅森尼数程序实现 /* 求梅森尼数:2^n-1 形的素数 c171 */ #include <stdio.h> #include <math.h> void main() { double t,m; int j,x,s,n; s=0; t=2; for(n=2;n<=50;n++). 50.

(10) 三、素数——上帝用来描写宇宙的文字. { Chapter 3. t=t*2; /* 累乘量 t 为 2^n */ m=t-1; x=0; for(j=3;j<sqrt(m)+1;j+=2) /* 试商法判别 m 是否素数 */ if(fmod(m,j)==0) {x=1;break;} if(x==0) /* 输出所求得的素数 */ { s=s+1; printf(" 2^%d-1=%.0f \n",n,m); } } printf(" 指数 n 于[2,50]中梅森尼数共有%d 个。",s); }. 4.程序运行结果与讨论 2^2-1=3 2^3-1=7 2^5-1=31 2^7-1=127 2^13-1=8191 2^17-1=131071 2^19-1=524287 2^31-1=2147483647 区间[2,50]中梅森尼数共有 8 个。 顺便指出,若 2^n-1 为梅森尼数,则 n 必为素数。以上程序的运行结果也可以验证 这一点。若需求更大的梅森尼数,指数 n 可限定一素数,以减少搜索量。 对于很大的素数 n,要判断 2^n-1 是否素数,工作量都艰辛无比,以上的穷举难以 胜任,需要一些特殊的理论和方法。1996 年美国数学家及程序设计师乔治·沃特曼编制 了一个梅森素数寻找程序,并把它放在网页上供数学家和数学爱好者免费使用。这就是 著名的“因特网梅森尼素数大搜索” (GIMPS)项目。该项目采取网格计算方式,利用大 量普通计算机的闲置时间来获得相当于超级计算机的运算能力。设在美国的电子新领域 基金会(EFF)于 1999 年 3 月向全世界宣布了为通过 GIMPS 项目来探寻新的更大的梅森 尼素数而设立的奖金。 它规定向第一个找到超过 100 万位数的个人或机构颁发 5 万美元。 后面的奖金依次为:超过 1000 万位数,10 万美元;超过 1 亿位数,15 万美元;超过 10 亿位数,25 万美元。目前,全球 18 万多名志愿者参加该项目,并动用 20 多万台计算机 联网来进行大规模的分布式计算,以寻找新的梅森尼素数。2008 年 8 月 23 日,美国加. 51.

(11) 趣味 C 程序设计. 州大学洛杉矶分校(UCLA)数学系的系统管理员 Edson Smith 在该系的一台计算机上利 Chapter 3. 用 GIMPS 软件发现了第 45 个梅森尼素数 243,112,609-1,它是第一个超过 1000 万位(有 12978189位)的素数,也是到目前为止已知的最大素数。有趣的是,稍后两个星期(9 月 6 日) ,德国 44 岁的电气工程师Hans-Michael Elvenich发现了比它小的第 46 个梅森 尼素数 237,156,667-1(有11185272 位)。不到一年,即 2009 年 4 月 12 日挪威的 IT 专业人 士 Odd Magnar Strindmo 发现了第 47 个梅森素数 242,643,801-1(有 12837064位) ,也是到 目前为止已知的第二大素数,但直到 6 月 12 日才通过法国的 Tony Reix 的验证。. 18 金蝉素数 1.问题提出 某古寺的一块石碑上依稀刻有一些神秘的自然数。 专家研究发现:这些数是由 1,3,5,7,9 这 5 个奇数字排列组成的 5 位素数,且 同时去掉它的最高位与最低位数字后的三位数还是素数,同时去掉它的高二位与低二位 数字后的一位数还是素数。因此,人们把这些神秘的素数称为金蝉素数,喻意金蝉脱壳 之后仍为美丽的金蝉。 试求出石碑上的金蝉素数。 2.设计要点 本题求解的金蝉素数是一种极为罕见的素数,实际上是素数的一个子集。 设置五位数 k 循环,对每一个 k,进行以下 4 步判别: (1)应用试商法检查 k 是否为素数。 (2)应用求余运算对素数 k“脱壳”之后的三位数 d 应用试商法判定 d 是否为 素数。 (3)对于 k 与 d 同时为素数,分离出其 5 个数字赋值给 a 数组。设置二重循环比 较,检查 k 是否存在相同数字。 (4)检查 k 的 5 个数字中是否存在偶数字,其中间数字 a(3)是否为 1 与 9(奇数 字中 1,9 非素数)。 设置标志量 t,t 赋初值 t=0。每一步检查若未通过,则 t=1。 最后若 t=0,则打印输出 k 即为金蝉素数。 3.金蝉素数程序实现 /* 金蝉素数 c181 */ #include <stdio.h>. 52.

(12) 三、素数——上帝用来描写宇宙的文字. Chapter 3. #include <math.h> void main() { int k,d,t,i,j,a[6]; printf(" 金蝉素数为:"); for(k=10001;k<99999;k+=2) { t=0; for(j=3;j<=sqrt(k);j+=2) if(k%j==0) /* 试商求素数 */ {t=1;break;} if(t==0) /* k 为 5 位素数 */ { a[1]=k%10; a[5]=k/10000; d=(k/10)%1000; for(j=2;j<=sqrt(d);j++) if(d%j==0) /* 试商求素数 */ {t=1; break;} } if(t==0) /* d 为 3 位素数 */ { a[2]=d%10; a[4]=d/100; a[3]=(d/10)%10; for(i=1;i<=4;i++) /* 比较确保没有相同数字 */ for(j=i+1;j<=5;j++) if(a[i]==a[j]) {t=1;break;} } if(t==0) { for(j=1;j<=5;j++) /* 排除偶数字与中间数字为 1,9 */ if(a[j]%2==0 || a[3]==1 || a[3]==9) { t=1;break;} } if(t==0) printf("%d ",k); /* 输出金蝉素数 */ } }. 4.程序运行结果 程序运行,得 5 个金蝉素数: 13597. 53791. 79531. 91573. 95713. 在输出的这 5 个金蝉素数中,13597 与 79531 是互逆的金蝉素数。 53.

(13) 趣味 C 程序设计. Chapter 3. 19 素数多项式 1.问题提出 早在 1772 年,欧拉就发现当 x=1,2,...,40 时二次多项式 x2  x  41的值都是素 数。从此,引发了关于素数多项式的探求。 设计程序验证以上多项式素数结论是否正确,并探索其他素数多项式。 2.验证欧拉素数多项式 (1)设计要点 为了验证二次三项式 y  x2  x  41 当 x 取值为 1~40 时 y 是否为素数。用通常 的试商判别 y 是不是素数,通过被 k=2,3,...,sqrt(y)的试商后,若 y 的值仍不变, 说明 y 是素数,并标注“素数” ;否则,打印 y 的因数分解式,注明 y“非素” 。 (2)验证素数多项式程序设计 /* 验证素数多项式 y=x^2-x+41 c191 */ #include "math.h" #include<stdio.h> void main() { int x,k,m,t; long y; m=0; printf( " y=x^2-x+41,当 x 取值在[1,40],y 的素数分布:\n"); for(x=1;x<=40;x++) { y=x*x-x+41; for(t=0,k=3;k<=sqrt(y);k++) if(y%k==0) { t=1;break;} if(t==0). /* t=0 时,y 为素数 */. { printf(" x=%2d 时,%4ld 素数.",x,y); m++; if(m%4==0) printf("\n"); }. 54.

(14) 三、素数——上帝用来描写宇宙的文字. else printf("x=%2d 时,%4ld=%d*%d. ",x,y,k,y/k); }. (3)程序运行结果. Chapter 3. }. 验证了当 x=1,2,...,40 时,二次多项式 x2  x  41的值均为素数。 3.寻求新的素数多项式 (1)素数多项式定义 分析二次三项式 y=x2-x+f 的取值: 当 f 为偶数时,无论 x 取哪些整数,y 的取值总为偶数,不可能为奇素数。 当 x=f 时,y 能被 f 整除,不是素数。 因此,二次三项式 y=x2-x+f(其中 f 大于 1 为奇数)只有当 x 取值为[1,f-1]时, 所对应的 y 值才有可能全为素数。 定义 y=x2-x+f 为素数多项式:其中 f 大于 1 为奇数,当 x=1,2,…,f-1 时,y 的 值都是素数。 试设计程序寻求新的素数多项式。 (2)程序设计 /* 寻求素数多项式 c192 */ #include "math.h" #include<stdio.h> void main() { int c,d,f,x,k,m,t; long y; printf( " 请确定区间[c,d]的下上限:"); scanf( " %d,%d",&c,&d); printf( " 常数项 f 在[%d,%d]中的素数多项式有:\n",c,d); if(c%2==0) c++;. 55.

(15) 趣味 C 程序设计. Chapter 3. for(f=c;f<=d;f+=2) { m=0; for(x=1;x<=f-1;x++) { y=x*x-x+f; for(t=0,k=3;k<=sqrt(y);k++) if(y%k==0) { t=1;break;} if(t==0) m++; /* t=0 时,y 为素数 */ else break; /* t=1 表示非素数多项式,返回进入下一个数的探索 */ } if(m==f-1) printf(" x^2-x+%d 是素数多项式!\n",f); } }. (3)程序运行示例 请确定输入区间[c,d]的下上限:11,99 常数项 f 在[11,99]中的素数多项式有: x^2-x+11 是素数多项式! x^2-x+17 是素数多项式! x^2-x+41 是素数多项式! 其中前两个是新的素数多项式。. 20 等差素数列 1.问题提出 我们知道,小于 10 的素数中有 3,5,7 组成等差数列。在 30 以内的素数中,有 11,17,23,29 组成等差数列。 在小于 2009 的所有素数中,最多有多少个素数成等差数列? 2.设计要点 为一般计,指定区间[w0,w]中有 n 个素数成等差数列,求 n 的最大值。 应 用 试 商 法 求 出 指 定 区 间 [w0,w] 中 的 所 有 奇 素 数 , 存 入 a 数 组 a(1),a(2),...,a(u)。 若以 m=a(n)为首项,公差 d=a(i)-a(n)为数组中两素数之差,用 h 标记等差数列中. 56.

(16) 三、素数——上帝用来描写宇宙的文字. 当前项的下标,m1 表等差数列中已有项数。如果 m1>max,则 max=m1,同时标记此时等 最后打印输出所求的项数最大值为 max 的一个素数等差数列。 3.等差素数列程序设计. Chapter 3. 差数列的首项 m=a(n)与公差 d1=d。. /* 等差素数列 c201 */ #include <math.h> #include <stdio.h> void main() { int d,i,j,k,m,n,t,h,d1,w0,w,m1,max,u=0; int a[10000]; printf("\n 求指定区间内等差素数列的最多项数."); printf("\n 请输入区间下限 w0,上限 w:"); scanf("%d,%d",&w0,&w); if(w0%2==0) w0++; for(k=w0;k<=w;k+=2) /* 求出区间内的奇素数 */ { for(t=0,j=3;j<=sqrt(k);j+=2) if(k%j==0) {t=1;break;} if(t==0) a[++u]=k; } max=0; for(n=1;n<=u-1;n++) /* a[n]为首项,d 为公差 */ for(j=n+1;j<=u;j++) { d=a[j]-a[n]; if(d>(w-w0)/3) break; /* 终止无意义的搜索 */ h=j; m1=2; for(i=j+1;i<=u;i++) if(a[i]-a[h]==d) {h=i;m1++;} if(max<m1) /* 比较得 max 最大值 */ { max=m1; m=a[n];d1=d; } } printf("\n 区间[%d,%d]内等差素数列最多有%d 项:\n",w0,w,max); for(i=0;i<=max-1;i++) printf("%d ",m+i*d1);. 57.

(17) 趣味 C 程序设计. printf("\n"); } Chapter 3. 4.程序运行示例 求指定区间内等差素数列的最多项数. 请输入区间下限 w0 及上限 w: 3,2009 区间[3,2009]内等差素数列最多有 9 项: 199 409 619 829 1039 1249 1459 1669 1879 请输入区间下限 w0 及上限 w: 100,1000 区间[101,1000]内等差素数列最多有 6 项: 107 137 167 197 227 257. 21 验证歌德巴赫猜想 1.问题提出 德国数学家哥德巴赫(Goldbach)在 1725 年写给欧拉(Euler)的信中提出了以下 猜想:任何大于 2 的偶数都是两个素数之和(俗称为 1+1) 。 两个多世纪过去了,这一猜想既无法证明,也没有被推翻。 试设计程序验证指定区间[c,d]上这一猜想是否成立。 2.设计要点 对于[c,d]上的所有偶数 i,分解为奇数 j 与 k=i-j(j=3,5,...,i/2)之和。用 试商法对奇数 j、k 作检验判别,即用奇数 x(3,5,...,sqrt(k))试商 j 与 k(试商 j*k 即可) 。 若存在 x 整除 j*k(标记 t=1) ,则 j 增 2,用一组新的奇数 j、k 再试。 若对某一组奇数 j、k,上述所有指定的 x 都不能整除 j*k,则偶数 i 找到分解的素 数 j、k,打印分解和式。 若某一偶数 i 穷举的所有奇数分解式都不存在同时为两素数情形,即已找到反例, 推翻了哥德巴赫猜想。打印找到反例信息(作为完整的验证程序设计,这一步骤不能省) 。 3.验证哥德巴赫猜想程序设计 /* 验证哥德巴赫猜想 c211 */ #include <stdio.h> #include <math.h> void main(). 58.

(18) 三、素数——上帝用来描写宇宙的文字. { Chapter 3. int c,d,i,j,k,t,x; printf( " 请输入区间上下限:"); scanf( " %d,%d",&c,&d); printf( " 在区间[%d,%d]中验证哥德巴赫猜想.\n",c,d); if(c%2!=0) c++; /* 确保 c 为偶数 */ for(i=c;i<=d;i+=2) { j=1; while(j<=i/2) { j=j+2; k=i-j; /* 把 i 分解为两整数 j 与 k 之和 */ t=0; for(x=3;x<=sqrt(k);x+=2) if((j*k)%x==0) /* 若 j 或 k 不是素数则 t=1 */ {t=1;break;} if(t==0) /* j 与 k 都是素数,则输出分解结果*/ { printf( " %d=%d+%d \n",i,j,k); break; } } } if(t==1) /* 偶数 i 不能分解为两素数之和,则输出反例*/ printf( " 找到反例:%d 不能分解为两素数之和。",i); else printf( " 哥德巴赫猜想在区间[%d,%d]中正确. \n",c,d); }. 4.程序运行示例与说明 请输入区间上下限:2000,2012 在区间[2000,2012]中验证哥德巴赫猜想. 2000=67+1933 2002=53+1949 2004=53+1951 2006=73+1933 2008=59+1949 2010=59+1951 2012=61+1951 哥德巴赫猜想在区间[2000,2012]中正确.. 59.

(19) 趣味 C 程序设计. 已有人在高速计算机上验证哥德巴赫猜想到了相当大的偶数,都没有找到这一猜想 Chapter 3. 的反例。但这仅仅是验证,并不能代替哥德巴赫猜想的证明,更不能据此验证断言哥德 巴赫猜想成立。. 22 合数世纪探求 1.问题的提出 运行以上求区间素数的程序可知 20 世纪的 100 个年号[1901, 2000]中有 13 个素数, 而 21 世纪的 100 个年号[2001,2100]中有 14 个素数。 那么,是否存在一个世纪的 100 个年号中一个素数都没有? 定义一个世纪的 100 个年号中不存在一个素数,即 100 个年号全为合数的世纪称为 合数世纪。设计程序探索最早的合数世纪。 这一与素数探求相关的趣题最早于 1996 年由杨克昌教授在《中国电脑教育报》 “编 程实践”栏目中提出并设计求解。 2.设计要点 应用穷举搜索,设置 a 世纪的 50 个奇数年号(偶数年号无疑均为合数)为 b,用 k 试商判别 b 是否为素数,用变量 s 统计这 50 个奇数中的合数的个数。 对于 a 世纪,若 s=50,即 50 个奇数都为合数,找到 a 世纪为最早的合数世纪,打 印输出后退出循环结束。 3.合数世纪程序设计 /* 合数世纪探求 c221 */ #include <stdio.h> #include <math.h> void main() { long a,b,k; int s,x; a=1; while (1) { a++;s=0; for(b=a*100-99;b<=a*100-1;b+=2) { x=0; for(k=3;k<=sqrt(b);k+=2). 60. /* 检验 a 世纪 */ /* 穷举 a 世纪奇数年号 b */.

(20) 三、素数——上帝用来描写宇宙的文字. Chapter 3. if(b%k==0) {x=1;break;} if(x==0)break; /* 当前为非合数世纪时,跳出循环进行下一个世纪的探求*/ s=s+x; /* 年号 b 为合数时,x=1,s 增 1 */ } if(s==50) /* s=50,即 50 个奇数均为合数 */ { printf("最早出现的合数世纪为 %ld 世纪!\n",a); break; } } }. 4.程序运行示例 运行程序,得 最早出现的合数世纪为 16719 世纪! 16719 世纪的 100 个年号为[1671801,1671900],这一区间中的 100 个整数全为合 数。这是一个非常漫长的年代,可谓天长地久,地老天荒! 5.最小的连续 n 个合数 最小的连续 3 个合数为[8,10],最小的连续 5 个合数为[24,28]。 试求出最小的连续 n 个合数(其中 n 是键盘输入的任意正整数) 。 这一问题与合数世纪问题密切相关,解的存在性勿庸置疑。对任意正整数 n,总存 在连续 n 个合数。例如,n=100 时,易知 101!+2,101!+3,...,101!+101 为连续 100 个合数,它们分别被 2,3,...,101 整除。 然而,要具体找出最小的连续 n 个合数谈何容易,这不是一般简单推理所能完成的。 (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)程序实现 61.

(21) 趣味 C 程序设计. Chapter 3. /* 求最小的连续 n 个合数 c222 */ #include <stdio.h> #include <math.h> void main() { long c,d,f,m,j; int t,n; printf(" 求最小的 n 个连续合数.\n"); printf(" 请输入 n(2—100):"); 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); getch();return; } if(t==0) f=m; /* 每求出一个素数 m 后赋值给 f */ } if(m>d) {c=d+2;d=c+10000;} /* 每一轮试商后改变 c,d 转下一轮 */ } }. (3)程序运行示例 求最小的 n 个连续合数,输入 n(2--100): 50 最小的 50 个连续合数区间为:[19610,19659]。 求最小的 n 个连续合数,输入 n(2--100): 100 最小的 100 个连续合数区间为: [370262,370361]。 建议:运行前面求区间素数的程序验证这些区间上是否存在素数。. 62.

(22)

參考文獻

相關文件

有一个人很喜欢抽烟,当家人反对时,他总是说:“我工作压力大,让

然而 ISDS 机制在实践中一些问题不断暴露出来,多数学者认为 ISDS

“告诉大家一个好消息和一个坏消息。好消息是下星期不考试了! ”同学们

「買一雙捐一雙」的承諾意味著,每當 Toms 賣出一雙鞋,他們就會捐一雙 鞋給落後國家的貧童;Toms 在今年春天已經售出了 1,000 萬雙鞋,這也意味著 世界上已經有

衡量一个地区或一个国家水资源的丰歉 程度的指标:

• 这幅由美国航空航天 局提供的影像中,南 极上空的臭氧层空洞 就像一个巨大的蓝色 水滴。美国航空航天 局的科学家2000年9 月8日宣布,南极上

一般说来, 对于一个区间上单调的函数的 图形都存在一个需要判别弧段位于相应的弦线

3.正弦函数y=Asin(ωx+φ)的图象之间的变换关系是学生最熟悉的一种伸缩变换.教 材从学生最熟悉的这一内容入手 ,分别比较了函数y=sin2x 和y=sinx 的图象之间的关