[摘录]一些基本算法1

摘录地址: http://vib.hit.edu.cn/vibbbs/dispbbs.asp?boardID=25&ID=2357&page=8
1.数论算法
求两数的最大公约数
function gcd(a,b:integer):integer;
begin
   if b=0 then gcd:=a
   else gcd:=gcd (b,a mod b);
end ;
求两数的最小公倍数
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.小范围内判断一个数是否为质数:  
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;    
B.判断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}
  
function prime(x:longint):integer;  
var i:integer;  
begin  
    prime:=false;  
    for i:=1 to l do  
        if pr[i] >=x then break  
        else if x mod pr[i]=0 then exit;  
        prime:=true;  
end;{prime}
  
2.3.4.求最小生成树  
A.Prim算法:  
procedure prim(v0:integer);  
var lowcost,closest:array[1..maxn] of integer;  
    i,j,k,min:integer;  
begin  
    for i:=1 to n do  
    begin  
        lowcost[i]:=cost[v0,i];  
        closest[i]:=v0;  
    end;  
    for i:=1 to n-1 do  
    begin   {寻找离生成树最近的未加入顶点k}  
        min:=maxlongint;  
        for j:=1 to n do  
           if (lowcost[j]< min) and (lowcost[j]< >0) then  
           begin  
              min:=lowcost[j];  
              k:=j;  
           end;  
        lowcost[k]:=0; {将顶点k加入生成树}  
     {生成树中增加一条新的边k到closest[k]}  
     {修正各点的lowcost和closest值}  
     for j:=1 to n do  
         if cost[k,j]< lwocost[j] then  
         begin  
            lowcost[j]:=cost[k,j];  
            closest[j]:=k;  
         end;  
     end;  
end;{prim}

B.Kruskal算法:(贪心)
    按权值递增顺序删去图中的边,若不形成回路则将此边加入最小生成树。
function find(v:integer):integer; {返回顶点v所在的集合}
var i:integer;
begin  
    i:=1;  
    while (i< =n) and (not v in vset[i]) do inc(i);  
         if i< =n then find:=i   else find:=0;
end;

procedure kruskal;
var tot,i,j:integer;
begin  
   for i:=1 to n do vset[i]:=[i];{初始化定义n个集合,第I个集合包含一个元素I}  
       p:=n-1; q:=1; tot:=0; {p为尚待加入的边数,q为边集指针}  
       sort;  
   {对所有边按权值递增排序,存于e[i]中,e[i].v1与e[i].v2为边I所连接的两个顶点的序号,e[i].len为第I条边的长度}  
   while p >0 do  
   begin  
       i:=find(e[q].v1);
       j:=find(e[q].v2);  
       if i< >j then  
       begin  
          inc(tot,e[q].len);  
          vset[i]:=vset[i]+vset[j];
          vset[j]:=[];  
          dec(p);  
       end;  
       inc(q);  
   end;  

5.最短路径  

A.标号法求解单源点最短路径:  
var   a:array[1..maxn,1..maxn] of integer;  
      b:array[1..maxn] of integer; {b[i]指顶点i到源点的最短路径}  
      mark:array[1..maxn] of boolean;    
procedure bhf;  
var   best,best_j:integer;  
begin  
      fillchar(mark,sizeof(mark),false);  
      mark[1]:=true;
      b[1]:=0;{1为源点}  
      repeat   best:=0;  
      for i:=1 to n do  
          If mark[i] then {对每一个已计算出最短路径的点}  
          for j:=1 to n do  
              if (not mark[j]) and (a[i,j] >0) then  
                  if (best=0) or (b[i]+a[i,j]< best) then  
                  begin  
                      best:=b[i]+a[i,j]; best_j:=j;  
                  end;  
                  if best >0 then  
                  begin  
                      b[best_j]:=best;
                      mark[best_j]:=true;  
                  end;  
     until best=0;  
end;{bhf}    

B.Floyed算法求解所有顶点对之间的最短路径:  
procedure floyed;  
begin  
   for I:=1 to n do  
       for j:=1 to n do  
           if a[I,j] >0 then
              p[I,j]:=I else p[I,j]:=0;  
              {p[I,j]表示I到j的最短路径上j的前驱结点}  
              for k:=1 to n do {枚举中间结点}  
                  for i:=1 to n do   for j:=1 to n do  
                      if a[i,k]+a[j,k]< a[i,j] then  
                      begin  
                         a[i,j]:=a[i,k]+a[k,j];  
                         p[I,j]:=p[k,j];  
                      end;  
end;

C. Dijkstra 算法:
类似标号法,本质为贪心算法。
var a:array[1..maxn,1..maxn] of integer;
    b,pre:array[1..maxn] of integer; {pre[i]指最短路径上I的前驱结点}
    mark:array[1..maxn] of boolean;
procedure dijkstra(v0:integer);
begin  
    fillchar(mark,sizeof(mark),false);  
    for i:=1 to n do  
    begin  
        d[i]:=a[v0,i];  
        if d[i]< >0 then
           pre[i]:=v0
        else
           pre[i]:=0;  
    end;  
    mark[v0]:=true;  
    repeat {每循环一次加入一个离1集合最近的结点并调整其他结点的参数}  
        min:=maxint;
        u:=0; {u记录离1集合最近的结点}  
        for i:=1 to n do  
            if (not mark[i]) and (d[i]< min) then  
            begin  
               u:=i; min:=d[i];  
            end;  
            if u< >0 then  
            begin  
               mark[u]:=true;  
               for i:=1 to n do  
                   if (not mark[i]) and (a[u,i]+d[u]< d[i]) then  
                   begin  
                      d[i]:=a[u,i]+d[u];  
                      pre[i]:=u;  
                   end;  
               end;  
     until u=0;
end;

D.计算图的传递闭包
Procedure Longlink;
Var T:array[1..maxn,1..maxn] of boolean;
Begin  
    Fillchar(t,sizeof(t),false);  
    For k:=1 to n do  
        For I:=1 to n do  
            For j:=1 to n do  
                T[I,j]:=t[I,j] or (t[I,k] and t[k,j]);
End;  

7.排序算法  

A.快速排序:  
procedure sort(l,r:integer);  
var i,j,mid:integer;  
begin  
    i:=l;j:=r;
    mid:=a[(l+r) div 2];  
    {将当前序列在中间位置的数定义为中间数}  
    repeat  
    while a[i]< mid do inc(i); {在左半部分寻找比中间数大的数}  
    while mid< a[j] do dec(j);{在右半部分寻找比中间数小的数}  
    if i< =j then  
    begin {若找到一组与排序目标不一致的数对则交换它们}  
       swap(a[i],a[j]);  
       inc(i);
       dec(j); {继续找}  
    end;  
    until i >j;  
    if l< j then
       sort(l,j); {若未到两个数的边界,则递归搜索左右区间}  
    if i< r then sort(i,r);  
end;{sort}

B.插入排序:

procedure insert_sort(k,m:word); {k为当前要插入的数,m为插入位置的指针}
var i:word; p:0..1;
begin  
    p:=0;  
    for i:=m downto 1 do  
        if k=a[i] then exit;  
        repeat   If k >a[m] then  
                 begin  
                    a[m+1]:=k; p:=1;  
                 end  
                 else  
                 begin  
                    a[m+1]:=a[m];
                    dec(m);  
                 end;  
        until p=1;
end;{insert_sort}  
l 主程序中为:  
   a[0]:=0;  
   for I:=1 to n do insert_sort(b[i],I-1);    

C.选择排序:  
procedure sort;  
var i,j,k:integer;  
begin  
     for i:=1 to n-1 do  
     begin  
         k:=i;  
         for j:=i+1 to n do  
            if a[j]< a[k] then
               k:=j; {找出a[i]..a[n]中最小的数与a[i]作交换}  
               if k< >i then  
               begin  
                  a[0]:=a[k];
                  a[k]:=a[i];
                  a[i]:=a[0];  
               end;  
     end;  
end;    

D. 冒泡排序  
procedure sort;  
var i,j,k:integer;  
begin  
    for i:=n downto 1 do  
        for j:=1 to i-1 do  
            if a[j] >a[i] then  
            begin  
               a[0]:=a[i];
               a[i]:=a[j];
               a[j]:=a[0];  
            end;  
end;    

E.堆排序:  
procedure sift(i,m:integer);{调整以i为根的子树成为堆,m为结点总数}  
var k:integer;  
begin  
    a[0]:=a[i];
    k:=2*i;{在完全二*树中结点i的左孩子为2*i,右孩子为2*i+1}  
    while k< =m do  
    begin  
        if (k< m) and (a[k]< a[k+1]) then inc(k);{找出a[k]与a[k+1]中较大值}  
        if a[0]< a[k] then  
        begin  
           a[i]:=a[k];
           i:=k;
           k:=2*i;  
        end  
        else
           k:=m+1;  
        end;  
        a[i]:=a[0]; {将根放在合适的位置}  
end;

procedure heapsort;
var j:integer;
begin  
    for j:=n div 2 downto 1 do sift(j,n);  
        for j:=n downto 2 do  
        begin  
            swap(a[1],a[j]);  
            sift(1,j-1);  
        end;
end;

F. 归并排序
{a为序列表,tmp为辅助数组}
procedure merge(var a:listtype; p,q,r:integer);
{将已排序好的子序列a[p..q]与a[q+1..r]合并为有序的tmp[p..r]}
var I,j,t:integer;
    tmp:listtype;
begin  
    t:=p;
    i:=p;
    j:=q+1;{t为tmp指针,I,j分别为左右子序列的指针}  
    while (t< =r) do  
    begin  
       if (i< =q){左序列有剩余} and ((j >r) or (a[i]< =a[j])) then  {满足取左边序列当前元素的要求}  
       begin  
          tmp[t]:=a[i]; inc(i);  
       end  
       else  
       begin  
          tmp[t]:=a[j];
          inc(j);  
       end;  
       inc(t);  
    end;  
    for i:=p to r do a[i]:=tmp[i];
end;{merge}

procedure merge_sort(var a:listtype; p,r: integer); {合并排序a[p..r]}
var q:integer;
begin  
    if p< >r then  
    begin  
       q:=(p+r-1) div 2;  
       merge_sort (a,p,q);  
       merge_sort (a,q+1,r);  
       merge (a,p,q,r);  
    end;
end;
{main}
begin  
    merge_sort(a,1,n);
end.


   writeln(tot);
end;      



欢迎大家访问我的个人网站 萌萌的IT人

posted on 2006-05-24 13:13 见酒就晕 阅读(174) 评论(0)  编辑  收藏 所属分类: 算法


只有注册用户登录后才能发表评论。


网站导航:
 
<2025年1月>
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678

导航

统计

常用链接

留言簿(3)

我参与的团队

随笔分类

随笔档案

文章分类

文章档案

收藏夹

BLOG

FRIENDS

LIFE

搜索

最新评论

阅读排行榜

评论排行榜