常用数论算法
1.求两数的最大公约数 function gcd(a,b:integer):integer; begin if b=0 then gcd:=a else gcd:=gcd (b,a mod b); end ; 2.求两数的最小公倍数 function lcm(a,b:integer):integer; begin if a<b then swap(a,b); lcm:=a; while lcm mod b>0 do inc(lcm,a); end; 或者利用 最小公倍数=a*b/最大公约数 3.素数的求法 1.小范围内判断一个数是否为质数: function prime (n: integer): Boolean; var I: integer; begin for I:=2 to trunc(sqrt(n)) do if n mod I=0 then begin prime:=false; exit; end; prime:=true; end; 2.判断longint范围内的数是否为素数(包含求50000以内的素数表): procedure getprime; var i,j:longint; p:array[1..50000] of boolean; begin fillchar(p,sizeof(p),true); p[1]:=false; i:=2; while i<50000 do begin if p[i] then begin j:=i*2; while j<50000 do begin p[j]:=false; inc(j,i); end; end; inc(i); end; l:=0; for i:=1 to 50000 do if p[i] then begin inc(l);pr[l]:=i; end; end;{getprime} begin for i:=1 to pnum do if sqr(p[i])<=x then begin if x mod p[i]=0 then begin IsPrime:=false; exit; end; end else begin IsPrime:=true; exit; end; IsPrime:=true; end;{prime} 3.利用随即函数判断longint范围内的数是否为素数 function f(a,b,n:longint):longint; //求a^b mod n var d,t:int64; begin d:=1;t:=a; while b>0 do begin if t=1 then begin f:=d;exit; end; if b mod 2 =1 then d:=d*t mod n; b:=b div 2; t:=t*t mod n; end; f:=d end; function judge(n:longint):boolean; //判断n是否为素数 n在longint范围内 var k:integer; bool:boolean; a:longint; begin randomize; bool:=true; for k:=1 to 3 do //适量调整k的大小 begin a:=random(n-2)+1; if (f(a,n-1,n) <> 1) then begin bool:=false; exit; //不是 则退出该子程序 使用break则只退出if循环而不退出子judge函数的运算过程 end; end; if bool then judge:=true //n 是素数 else judge:=false; //n 不是素数 ; end; 4.求前n个素数: program BasicMath_Prime; const maxn=1000; var pnum,n:longint; p:array[1..maxn] of longint; function IsPrime(x:longint):boolean; var i:integer; begin for i:=1 to pnum do if sqr(p[i])<=x then begin if x mod p[i]=0 then begin IsPrime:=false; exit; end; end else begin IsPrime:=true; exit; end; IsPrime:=true; end; procedure main; var x:longint; begin pnum:=0; x:=1; while(pnum<n) do begin inc(x); if IsPrime(x) then begin inc(pnum); p[pnum]:=x; end; end; end; procedure out; var i,t:integer; begin for i:=1 to n do begin write(p[i]:5);t:=t+1; if t mod 10=0 then writeln; end; end; begin readln(n); main; out; end. 5.求不大于n的所有素数 program sushu3; const maxn=10000; var i,k,n:integer; a:array[1..maxn] of integer; begin readln(n); for i:=1 to n do a[i]:=i; a[1]:=0; i:=2; while i<n do begin k:=2*i; while k<=n do begin a[k]:=0; k:=k+i; end; i:=i+1; while (a[i]=0) and (i<n) do i:=i+1; end; k:=0; for i:=1 to n do if a[i]<>0 then begin write(a[i]:5); k:=k+1; if k mod 10 =0 then writeln; end end. 6.将整数分解质因数的积 program BasicMath_PolynomialFactors; const maxp=1000; var pnum,n:longint; num,p:array[1..maxp] of longint; procedure main; var x:longint; begin fillchar(num,sizeof(num),0); fillchar(p,sizeof(p),0); pnum:=0; x:=1; while(n>1) do begin inc(x); if n mod x=0 then begin inc(pnum); p[pnum]:=x; while(n mod x=0) do begin n:=n div x; inc(num[pnum]); end; end; end; end; procedure out; var j,i:integer; begin for i:=1 to pnum do for j:=1 to num[i] do write(p[i]:5); writeln; end; begin main; out; end. 6 排列组合 (一) 排列数 [算法描述] 排列数公式 [源程序] function A(m,n:integer):integer; var ans,i:integer; begin ans:=1; for i:=1 to m do begin ans:=ans*n; n:=n-1; end; A:=ans; end; (二) 组合数 [算法描述] 组合数公式 [源程序] function C(m,n:integer):integer; var ans,i:integer; begin ans:=1; for i:=1 to m do begin ans:=ans*n; n:=n-1; end; for i:=1 to m do ans:=ans/i; C:=ans; end; (三) 全排列算法 [算法描述] 1.1,2……N依次赋给a[1]至a[n],输出第一种排列; 2.构造下一种全排列,分四步完成: (1) i的初值为1,在a[1]至a[n]中搜索找出相应的i,使i是a[k]>a[k-1]的k中最大的,即i=max{k|a[k]>a[k-1],k=2,3…n}; (2) 在a[x]至a[n]中搜索找出相应的j,使j是a[k]>a[i-1]的k中最大的,即j=max{k|a[k]>a[i-1],k=i,i+1…n}; (3) 交换a[i-1]与a[j]形成新的序列; (4) 对新的序列从 a[i+1]……a[n]进行逆序处理,输出相应序列. 3.重复2直到i=1时结束 [源代码]: program quanpailie; const maxn=20; type arrayt=array[1..maxn]of integer; var i,n,temp:integer; procedure inverse(var num:arrayt;x:integer); //对num[x]~num[n]作逆序处理 var numt:arrayt; i:integer; begin for i:=1 to n do numt[i]:=num[i]; for i:=0 to n-x do num[x+i]:=numt[n-i]; end; procedure arrange(n:integer); var num:arrayt; i,x,y:byte; temp:integer; begin num[0]:=0; for i:=1 to n do begin num[i]:=i; write(num[i],' '); end; writeln; repeat for i:=1 to n do if num[i]>num[i-1] then x:=i; for i:=x to n do if num[i]>num[x-1] then y:=i; if x>1 then begin temp:=num[x-1];num[x-1]:=num[y];num[y]:=temp; inverse(num,x); //对num[x]~num[n]作逆序处理 for i:=1 to n do write(num[i],' '); //输出当前序列 writeln; end; until x=1; end; begin {main} assign(input,'input.dat'); reset(input); assign(output,'output.dat');rewrite(output); readln(n); arrange(n); close(input);close(output); end. 7 进制转换 (一) 十进制转N进制 [算法描述] 辗转相除法. [源程序] function int_to_n(x:cardinal; n:byte):string; var a:array[1..255] of byte; ans:string; count,i:byte; begin ans:=''; count:=0; if x=0 then ans:='0'; while x>0 do begin count:=count+1; a[count]:=x mod n; x:=x div n; end; for i:=count downto 1 do if a[i]<10 then ans:=ans+chr(ord('0')+a[i]) else ans:=ans+chr(ord('a')-10+a[i]); int_to_n:=ans; end; (二) N进制转十进制 [算法描述] 加权. [源程序] function n_to_int(x:string; n:byte):cardinal; var a:array[1..255] of byte; ans,y:cardinal; count,i,j:byte; begin ans:=0; for i:=1 to length(x) do if x[i] in ['0'..'9'] then a[i]:=ord(x[i])-ord('0') else a[i]:=ord(x[i])-ord('a')+10; count:=0; for i:=length(x) downto 1 do begin y:=1; for j:=1 to count do y:=y*n; count:=count+1; ans:=ans+y*a[i]; end; n_to_int:=ans; end; (三) 八进制数或十六进制数转换为二进制数,二进制数转换成八进制数和十六进制数的通用程序(仅在整数范围)。如: 输入一个数m : ABC 输入此数的进制n : 16 输出: ABC(16)=101010111100(2) 又如输入一个数m : 101010111100 输入此数的进制n : 2 输出: 101010111100(2)=ABC(16)=5274(8) 【程序清单】 PROGRAM P12_5b; CONST s0=['0'..'9','A'..'F']; c:ARRAY [0..15] OF STRING[4]=('0000','0001','0010','0011','0100','0101', '0110','0111','1000','1001','1010','1011','1100','1101','1110','1111'); c0:ARRAY [1..7] OF STRING=('1','10','11','100','101','110','111'); VAR i,j,k,n,l:Integer; f:Boolean; s,s1,ss:STRING; ch:Char; BEGIN assign(input,'input.dat'); reset(input); assign(output,'output.dat');rewrite(output); ss:='0123456789ABCDEF'; Write('Input a string : '); Readln(s); {'输入一个数串} REPEAT Write('Input a number : '); Readln(n) {'输入一个此数串进制 } UNTIL n IN [2,8,16]; l:=Length(s); i:=1; f:=True; WHILE (i<=l) AND f DO BEGIN {'检测数串} ch:=Upcase(s[i]); Write(ch); IF n=16 THEN IF NOT(ch IN s0) THEN f:=False; {'如f为假输出出错信息} IF n=8 THEN IF NOT(ch IN ['0'..'7']) THEN f:=False; IF n=2 THEN IF NOT(ch IN ['0','1']) THEN f:=False; i:=i+1; END; Write('(',n,') = '); IF NOT f THEN BEGIN Writeln('Data Error !'); Readln; Exit END; CASE n OF {'分情况处理} 2:BEGIN {'输入的是二进制数 } i:=1; j:=l MOD 4; {'按每四位分,取余数j} WHILE i<l DO BEGIN {'用当循环来处理} s1:=Copy(s,i,j); {'取出子串} IF j<4 THEN {'头一个子串因前面没有无用的0的,转换时分别处理 } FOR k:=1 TO 7 DO IF s1=c0[k] THEN Write(k) ELSE ELSE {'以后的子串每四位对应一个十六进制数} FOR k:=0 TO 15 DO IF s1=c[k] THEN Write(ss[k+1]); i:=i+j; j:=4; {'除头一个子串外,以后按每四位截取} END; Write('(',16,') = '); {'十六进制数输出结束 } i:=1; j:=l MOD 3; {'按每三位分, 取余数j } WHILE i<l DO BEGIN s1:=Copy(s,i,j); IF j<3 {'头一个子串因前面没有无用的0,转换时分别处理 } THEN FOR k:=1 TO 7 DO IF s1=c0[k] THEN Write(k) ELSE ELSE FOR k:=0 TO 7 DO IF s1=Copy(c[k],2,4) THEN Write(ss[k+1]); i:=i+j; j:=3; {'除头一个子串外,以后按每三位截取} END; Writeln('(',8,')'); {'八进制数输出结束} END; 8,16: {'输入的是八或十六进制数} FOR i:=1 TO l DO BEGIN ch:=Upcase(s[i]); j:=Ord(ch)-48; {'先转成大写,再转成对应的数} IF ch IN ['A'..'F'] THEN j:=j-7; IF i=1 {'头一个数转换成二进制数,前面无用的0不输出} THEN IF ch IN ['1'..'7'] THEN Write(c0[j]) ELSE Write(c[j]) ELSE IF n=16 THEN Write(c[j]) {'转成十六进制数} ELSE Write(Copy(c[j],2,4)) {'转成八进制数} END END; IF n IN [8,16] THEN Writeln('(',2,')'); close(input);close(output); END. (四) 不同进制数之间实数转换的通用程序。 输入n进制的数m与要转换的p进制的输出。 如: 输入一个数m : ABC.CBA 输入此数的进制n : 16 输入要转换成的数的进制p : 2 输出: ABC.ABC(16)=101010111100.11001011101(2) 【程序清单】 PROGRAM P12_5A; TYPE ss=STRING[30]; VAR m,m1,a,s:ss; m0,n,p,i,j,t,s1,x:Integer; mm,d:LongInt; mr:Real; PROCEDURE Zhuan(ch:Char); {过程—数字符转换成数} BEGIN j:=Ord(ch)-48; {数字符转换成数} IF ch IN ['A'..'F'] THEN j:=j-7; {数字符转换成数} IF (j<0) AND (j>=n) THEN {出界输出出错信息,程序终止} BEGIN Writeln('Data errer !'); Readln; EXIT END; END; PROCEDURE Xiao(m:ss); {过程—小数部分的转换} BEGIN mr:=0; m0:=Length(m); t:=n; {初始化} IF n=10 THEN Val(m,mr,t) ELSE {如是十进制数,就直接把数串转换成数} FOR i:=2 TO m0 DO BEGIN {否则把m,先转换成十进制小数,m[1]是小数点} Zhuan(m[i]); {调用字符转为数的过程} mr:=mr+j/t; t:=t*n {按权一一展开,累加到mr中} END; m:='.'; {再把mr转换成p进制的数串} WHILE mr>0.00001 DO BEGIN {精度要求5位小数} mr:=mr*p; x:=Trunc(mr); {用乘p取整法,取出一位整数} m:=m+s[x+1]; mr:=mr-x; {按顺序一一连入m中} END; Write(m) {输出p进制的数串m} END; BEGIN s:='0123456789ABCDEF'; {s字符串用以对应数制用} Write('Input m : '); Readln(m); {输入原数} Write('Input n : '); Readln(n); {输入原数的进制} Write('Input p : '); Readln(p); {输入要转换成的数的进制} m0:=Length(m); FOR i:=1 TO m0 DO m[i]:=Upcase(m[i]);{转成大写} Write(m,'(',n,') = '); {输出要转换的原数及其进制} x:=Pos('.',m); {找出小数点的位置。如没有小数点x为0} IF x<>0 {如有小数部分,就把小数(m1)与整数(m)分离} THEN BEGIN m1:=Copy(m,x,m0+1-x); m:=Copy(m,1,x-1) END; t:=1; mm:=0; m0:=Length(m); {先做整数部分的转换} IF n<>10 THEN {把数串m转换成十进制数mm} FOR i:=m0 DOWNTO 1 DO BEGIN Zhuan(m[i]); {调用字符转为数的过程} mm:=mm+j*t; t:=t*n {按权一一展开,累加到mm中} END ELSE Val(m,mm,t); {如是十进制就直接把数串转成数} IF p<>10 THEN BEGIN {再把mm转换成p进制的数串} m:=''; WHILE mm>0 DO BEGIN {反序累加到m中} m:=s[mm MOD p+1]+m; mm:=mm DIV p END; END ELSE Str(mm,m); {如mm是十进制数就直接转成数} IF m<>'0' THEN Write(m); {先输出整数部分转换的结果} IF x<>0 THEN Xiao(m1); {如有小数部分,就调用过程Xiao} Writeln('(', p,')'); Readln; {最后输出要转换成的数制信息} END.