竞赛:| 全国大学生数模竞赛 | 全国研究生数模竞赛 | 全国大学生电工数模竞赛 | 美国"MCM/ICM" 竞赛 |
 资讯:| 数学理论 | 交叉学科 | 基础教育 | 考研数学 | 学术动态 | 编程交流 | 网络安全 | 经验技巧 |
 下载:| 数 学 篇 | 算 法 篇 | 建 模 篇 | 编 程 篇 | 数 据 篇 | 软 件 篇 | 考 研 篇 | 交叉学科 |
 视频:| 大学数学 | 大学英语 | 计 算 机 | 法律课程 | 政治课程 | 经济管理 | 数学建模 | 高考数学 |
 功能:| 矩阵论坛 | 学校协会 | 挑 战 赛 | 人才招聘 | 数学问吧 | "MC"理工浏览器 | "MCQ"即时通讯 |

 
会员中心
社区论坛
加入收藏
联系我们
您现在的位置: 数学中国 >> 资讯无限 >> 数学理论 >> 教辅参考 >> 正文
【字体:           
 
一些基本算法 的讨论
作者:李达    文章来源:李达    点击数:    更新时间:2005-6-23

基本算法
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;  
   writeln(tot);
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.

9.树的遍历顺序转换  

A. 已知前序中序求后序  
procedure Solve(pre,mid:string);  
var i:integer;  
begin  
    if (pre='') or (mid='') then exit;  
    i:=pos(pre[1],mid);  
    solve(copy(pre,2,i),copy(mid,1,i-1));  
    solve(copy(pre,i+1,length(pre)-i),copy(mid,i+1,length(mid)-i));  
    post:=post+pre[1]; {加上根,递归结束后post即为后序遍历}  
end;    

B.已知中序后序求前序  
procedure Solve(mid,post:string);  
var i:integer;  
begin  
    if (mid='') or (post='') then exit;  
    i:=pos(post[length(post)],mid);  
    pre:=pre+post[length(post)]; {加上根,递归结束后pre即为前序遍历}  
    solve(copy(mid,1,I-1),copy(post,1,I-1));  
    solve(copy(mid,I+1,length(mid)-I),copy(post,I,length(post)-i));  
end;    

C.已知前序后序求中序    
function ok(s1,s2:string):boolean;  
var i,l:integer;
    p:boolean;  
begin  
    ok:=true;  
    l:=length(s1);  
    for i:=1 to l do  
    begin  
        p:=false;  
        for j:=1 to l do  
        if s1[i]=s2[j] then p:=true;  
          if not p then  
          begin  
             ok:=false;exit; 
          end;  
        end;  
    end;    

procedure solve(pre,post:string);  
var i:integer;  
begin  
    if (pre='') or (post='') then exit;  
    i:=0;  
    repeat  
       inc(i);  
    until ok(copy(pre,2,i),copy(post,1,i));  
    solve(copy(pre,2,i),copy(post,1,i));  
    midstr:=midstr+pre[1];  
    solve(copy(pre,i+2,length(pre)-i-1),copy(post,i+1,length(post)-i-1));  
end;    

10.求图的弱连通子图(DFS)  
procedure dfs ( now,color: integer);  
begin  
    for i:=1 to n do  
        if a[now,i] and c[i]=0 then  
        begin  
           c[i]:=color;  
           dfs(I,color);  
        end;  
end;    

12.进制转换  
A.整数任意正整数进制间的互化    
NOIP1996数制转换  
设字符串A$的结构为: A$='mp'  
其中m为数字串(长度< =20),而n,p均为1或2位的数字串(其中所表达的内容在2-10之间)
程序要求:从键盘上读入A$后(不用正确性检查),将A$中的数字串m(n进制)以p进制的形式输出.
例如:A$='48< 10 >8'   其意义为:将10进制数48,转换为8进制数输出.  
输出结果:48< 10 >=60< 8 >    
B.实数任意正整数进制间的互化  
C.负数进制:   NOIP2000   设计一个程序,读入一个十进制数的基数和一个负进制数的基数,
并将此十进制数转换为此负 进制下的数:-R∈{-2,-3,-4,....-20}            

13.全排列与组合的生成   排列的生成:(1..n)  
procedure solve(dep:integer);  
var   i:integer;  
begin  
      if dep=n+1 then
      begin
         writeln(s);
         exit;
      end;  
      for i:=1 to n do  
         if not used[i] then  
         begin  
            s:=s+chr(i+ord('0'));
            used[i]:=true;  
            solve(dep+1);  
            s:=copy(s,1,length(s)-1);
            used[i]:=false;  
         end;  
end;  

组合的生成(1..n中选取k个数的所有方案)  
procedure solve(dep,pre:integer);  
var   i:integer;  
begin  
      if dep=k+1 then
      begin
         writeln(s);
         exit;
      end;  
      for i:=1 to n do  
         if (not used[i]) and (i >pre) then  
         begin  
             s:=s+chr(i+ord('0'));
             used[i]:=true;  
             solve(dep+1,i);  
             s:=copy(s,1,length(s)-1);
             used[i]:=false;  
         end;  
end;        

14 递推关系   计算字串序号模型   USACO1.2.5 StringSobits  
长度为N (N< =31)的01串中1的个数小于等于L的串组成的集合中找出按大小排序后的第I个01串。
数字划分模型
*NOIP2001数的划分
将整数n分成k份,且每份不能为空,
任意两种分法不能相同(不考虑顺序)。
d[0,0]:=1;
for p:=1 to n do
    for i:=p to n do
       for j:=k downto 1 do inc(d[i,j],d[i-p,j-1]);
           writeln(d[n,k]);
*变形1:考虑顺序
d[ i, j] : = d [ i-k, j-1] (k=1..i)
*变形2:若分解出来的每个数均有一个上限m
d[ i, j] : = d [ i-k, j-1] (k=1..m)

15.算符优先法求解表达式求值问题
const maxn=50;
var s1:array[1..maxn] of integer; {s1为数字栈}
    s2:array[1..maxn] of char; {s2为算符栈}
    t1,t2:integer; {栈顶指针}
procedure calcu;
var x1,x2,x:integer;
    p:char;
begin  
    p:=s2[t2];
    dec(t2);  
    x2:=s1[t1];
    dec(t1);  
    x1:=s1[t1];
    dec(t1);  
    case p of  
      '+':x:=x1+x2;  
      '-':x:=x1-x2;  
      '*':x:=x1*x2;  
      '/':x:=x1 div 2;  
    end;  
    inc(t1);
    s1[t1]:=x;
end;
procedure work;
var c:char;
    v:integer;
begin  
    t1:=0;
    t2:=0;  
    read(c);  
    while c< >';' do  
       case c of 
       '+','-':  
       begin  
           while (t2 >0) and (s2[t2]< >'(') do calcu;  
               inc(t2);s2[t2]:=c;  
               read(c);  
       end ;  
       '*','/': 
       begin  
           if (t2 >0) and ((s2[t2]='*') or (s2[t2]='/')) then calcu;  
           inc(t2);s2[t2]:=c;  
           read(c);  
       end;  
       '(':
       begin
           inc(t2);
           s2[t2]:=c;
           read(c);
       end;  
       ')': 
       begin  
           while s2[t2]< >
       '(' do calcu;  
           dec(t2);
           read(c);  
       end;  
       '0'..'9': 
       begin  
           v:=0;  
           repeat  
              v:=10*v+ord(c)-ord('0');  
              read(c);  
           until (c< '0') or (c >'9');  
           inc(t1);
           s1[t1]:=v;  
       end;  
      end;  
      while t2 >0 do calcu;  
           writeln(s1[t1]);
end;

16.查找算法  
折半查找  
function binsearch(k:keytype):integer;  
var low,hig,mid:integer;  
begin  
    low:=1;
    hig:=n;  
    mid:=(low+hig) div 2;  
    while (a[mid].key< >k) and (low< =hig) do 
    begin  
         if a[mid].key >k then hig:=mid-1  
         else low:=mid+1;  
              mid:=(low+hig) div 2;  
         end;  
         if low >hig then mid:=0;  
            binsearch:=mid;  
end;    
树形查找  
二叉排序树:每个结点的值都大于其左子树任一结点的值而小于其右子树任一结点的值。  
查找  
function treesrh(k:keytype):pointer;  
var q:pointer;  
begin  
    q:=root;  
    while (q< >nil) and (q^.key< >k) do   if k<
       q^.key then q:=q^.left   else q:=q^.right;  
    treesrh:=q;  
end;

文章录入:smtg212    责任编辑:smtg212  
  • 上一篇文章:

  • 下一篇文章:
  • 发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
    推 荐 文 章
    更多内容
     
    热 门 文 章  
    更多内容
     

    费马小定理
    相 关 文 章
    更多内容
     
    Matlab实验
    转数与合数的转换
    模拟退火算法
    遗传算法
    C++版的常用数值计算算法
    问国人何时能解此算法?
    | 设为首页 | 加入收藏 | 联系站长 | 友情链接 | 版权申明 | 管理登录 |