常用数论算法

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.
                             

 


                            

posted @ 2015-11-06 10:31  OI_songer  阅读(563)  评论(0编辑  收藏  举报