gghhjj 发表于 2005-8-28 14:56

[分享]一些基本算法

1.数论算法 <BR>求两数的最大公约数 <BR>function gcd(a,b:integer):integer; <BR>begin<BR>   if b=0 then gcd:=a <BR>   else gcd:=gcd (b,a mod b); <BR>end ; <BR>求两数的最小公倍数 <BR>function lcm(a,b:integer):integer;<BR>begin<BR>   if a&amp;lt; b then swap(a,b); <BR>      lcm:=a; <BR>   while lcm mod b &amp;gt;<BR>   0 do inc(lcm,a); <BR>end; <BR>素数的求法 <BR>A.小范围内判断一个数是否为质数:<BR>function prime (n: integer): Boolean; <BR>var I: integer; <BR>begin <BR>   for I:=2 to trunc(sqrt(n)) do <BR>      if n mod I=0 then <BR>      begin <BR>         prime:=false; exit; <BR>      end;   <BR>   prime:=true;   <BR>end;   <BR>B.判断longint范围内的数是否为素数(包含求50000以内的素数表):   <BR>procedure getprime;   <BR>var i,j:longint;   <BR>    p:array of boolean;   <BR>begin   <BR>    fillchar(p,sizeof(p),true);   <BR>    p:=false;   <BR>    i:=2;   <BR>    while i&amp;lt; 50000 do   <BR>    begin   <BR>       if p then   <BR>       begin   <BR>          j:=i*2;   <BR>          while j&amp;lt; 50000 do   <BR>          begin   <BR>             p:=false;   <BR>             inc(j,i);   <BR>          end;   <BR>       end;   <BR>       inc(i);   <BR>    end;   <BR>    l:=0;   <BR>    for i:=1 to 50000 do   <BR>       if p then   <BR>       begin   <BR>          inc(l);<BR>          pr:=i;   <BR>       end;   <BR>    end;{getprime}<BR>   <BR>function prime(x:longint):integer;   <BR>var i:integer;   <BR>begin   <BR>    prime:=false;   <BR>    for i:=1 to l do   <BR>      if pr &amp;gt;=x then break   <BR>      else if x mod pr=0 then exit;   <BR>      prime:=true;   <BR>end;{prime} <BR>   <BR>2.3.4.求最小生成树   <BR>A.Prim算法:   <BR>procedure prim(v0:integer);   <BR>var lowcost,closest:array of integer;   <BR>    i,j,k,min:integer;   <BR>begin   <BR>    for i:=1 to n do   <BR>    begin   <BR>      lowcost:=cost;   <BR>      closest:=v0;   <BR>    end;   <BR>    for i:=1 to n-1 do   <BR>    begin   {寻找离生成树最近的未加入顶点k}   <BR>      min:=maxlongint;   <BR>      for j:=1 to n do   <BR>         if (lowcost&amp;lt; min) and (lowcost&amp;lt; &amp;gt;0) then   <BR>         begin   <BR>            min:=lowcost;   <BR>            k:=j;   <BR>         end;   <BR>      lowcost:=0; {将顶点k加入生成树}   <BR>   {生成树中增加一条新的边k到closest}   <BR>   {修正各点的lowcost和closest值}   <BR>   for j:=1 to n do   <BR>         if cost&amp;lt; lwocost then   <BR>         begin   <BR>            lowcost:=cost;   <BR>            closest:=k;   <BR>         end;   <BR>   end;   <BR>end;{prim} <BR>
<P>B.Kruskal算法:(贪心) <BR>    按权值递增顺序删去图中的边,若不形成回路则将此边加入最小生成树。 <BR>function find(v:integer):integer; {返回顶点v所在的集合} <BR>var i:integer; <BR>begin   <BR>    i:=1;   <BR>    while (i&amp;lt; =n) and (not v in vset) do inc(i);   <BR>         if i&amp;lt; =n then find:=i   else find:=0; <BR>end; </P>
<P>procedure kruskal; <BR>var tot,i,j:integer; <BR>begin   <BR>   for i:=1 to n do vset:=;{初始化定义n个集合,第I个集合包含一个元素I}   <BR>       p:=n-1; q:=1; tot:=0; {p为尚待加入的边数,q为边集指针}   <BR>       sort;   <BR>   {对所有边按权值递增排序,存于e中,e.v1与e.v2为边I所连接的两个顶点的序号,e.len为第I条边的长度}   <BR>   while p &amp;gt;0 do   <BR>   begin   <BR>       i:=find(e.v1);<BR>       j:=find(e.v2);   <BR>       if i&amp;lt; &amp;gt;j then   <BR>       begin   <BR>          inc(tot,e.len);   <BR>          vset:=vset+vset;<BR>          vset:=[];   <BR>          dec(p);   <BR>       end;   <BR>       inc(q);   <BR>   end;   <BR>   writeln(tot); <BR>end;       </P>

gghhjj 发表于 2005-8-28 14:57

回复:(ggggggl)[分享]一些基本算法

<P>5.最短路径   </P>
<P>A.标号法求解单源点最短路径:   <BR>var   a:array of integer;   <BR>      b:array of integer; {b指顶点i到源点的最短路径}   <BR>      mark:array of boolean;   <BR>procedure bhf;   <BR>var   best,best_j:integer;   <BR>begin   <BR>      fillchar(mark,sizeof(mark),false);   <BR>      mark:=true; <BR>      b:=0;{1为源点}   <BR>      repeat   best:=0;   <BR>      for i:=1 to n do   <BR>          If mark then {对每一个已计算出最短路径的点}   <BR>          for j:=1 to n do   <BR>            if (not mark) and (a &amp;gt;0) then   <BR>                  if (best=0) or (b+a&amp;lt; best) then   <BR>                  begin   <BR>                      best:=b+a; best_j:=j;   <BR>                  end;   <BR>                  if best &amp;gt;0 then   <BR>                  begin   <BR>                      b:=best;<BR>                      mark:=true;   <BR>                  end;   <BR>   until best=0;   <BR>end;{bhf}   </P>
<P>B.Floyed算法求解所有顶点对之间的最短路径:   <BR>procedure floyed;   <BR>begin   <BR>   for I:=1 to n do   <BR>       for j:=1 to n do   <BR>         if a &amp;gt;0 then <BR>            p:=I else p:=0;   <BR>            {p表示I到j的最短路径上j的前驱结点}   <BR>            for k:=1 to n do {枚举中间结点}   <BR>                  for i:=1 to n do   for j:=1 to n do   <BR>                      if a+a&amp;lt; a then   <BR>                      begin   <BR>                         a:=a+a;   <BR>                         p:=p;   <BR>                      end;   <BR>end; </P>
<P>C. Dijkstra 算法: <BR>类似标号法,本质为贪心算法。 <BR>var a:array of integer; <BR>    b,pre:array of integer; {pre指最短路径上I的前驱结点} <BR>    mark:array of boolean; <BR>procedure dijkstra(v0:integer); <BR>begin   <BR>    fillchar(mark,sizeof(mark),false);   <BR>    for i:=1 to n do   <BR>    begin   <BR>      d:=a;   <BR>      if d&amp;lt; &amp;gt;0 then <BR>         pre:=v0 <BR>      else <BR>         pre:=0;   <BR>    end;   <BR>    mark:=true;   <BR>    repeat {每循环一次加入一个离1集合最近的结点并调整其他结点的参数}   <BR>      min:=maxint; <BR>      u:=0; {u记录离1集合最近的结点}   <BR>      for i:=1 to n do   <BR>            if (not mark) and (d&amp;lt; min) then   <BR>            begin   <BR>               u:=i; min:=d;   <BR>            end;   <BR>            if u&amp;lt; &amp;gt;0 then   <BR>            begin   <BR>               mark:=true;   <BR>               for i:=1 to n do   <BR>                   if (not mark) and (a+d&amp;lt; d) then   <BR>                   begin   <BR>                      d:=a+d;   <BR>                      pre:=u;   <BR>                   end;   <BR>               end;   <BR>   until u=0; <BR>end; </P>
<P>D.计算图的传递闭包 <BR>Procedure Longlink; <BR>Var T:array of boolean; <BR>Begin   <BR>    Fillchar(t,sizeof(t),false);   <BR>    For k:=1 to n do   <BR>      For I:=1 to n do   <BR>            For j:=1 to n do   <BR>                T:=t or (t and t); <BR>End;   </P>
<P>7.排序算法   </P>
<P>A.快速排序:   <BR>procedure sort(l,r:integer);   <BR>var i,j,mid:integer;   <BR>begin   <BR>    i:=l;j:=r; <BR>    mid:=a[(l+r) div 2];   <BR>    {将当前序列在中间位置的数定义为中间数}   <BR>    repeat   <BR>    while a&amp;lt; mid do inc(i); {在左半部分寻找比中间数大的数}   <BR>    while mid&amp;lt; a do dec(j);{在右半部分寻找比中间数小的数}   <BR>    if i&amp;lt; =j then   <BR>    begin {若找到一组与排序目标不一致的数对则交换它们}   <BR>       swap(a,a);   <BR>       inc(i);<BR>       dec(j); {继续找}   <BR>    end;   <BR>    until i &amp;gt;j;   <BR>    if l&amp;lt; j then <BR>       sort(l,j); {若未到两个数的边界,则递归搜索左右区间}   <BR>    if i&amp;lt; r then sort(i,r);   <BR>end;{sort} </P>
<P>B.插入排序: </P>
<P>procedure insert_sort(k,m:word); {k为当前要插入的数,m为插入位置的指针} <BR>var i:word; p:0..1; <BR>begin   <BR>    p:=0;   <BR>    for i:=m downto 1 do   <BR>      if k=a then exit;   <BR>      repeat   If k &amp;gt;a then   <BR>               begin   <BR>                  a:=k; p:=1;   <BR>               end   <BR>               else   <BR>               begin   <BR>                  a:=a; <BR>                  dec(m);   <BR>               end;   <BR>      until p=1; <BR>end;{insert_sort}   <BR>l 主程序中为:   <BR>   a:=0;   <BR>   for I:=1 to n do insert_sort(b,I-1);   </P>
<P>C.选择排序:   <BR>procedure sort;   <BR>var i,j,k:integer;   <BR>begin   <BR>   for i:=1 to n-1 do   <BR>   begin   <BR>         k:=i;   <BR>         for j:=i+1 to n do   <BR>            if a&amp;lt; a then <BR>               k:=j; {找出a..a中最小的数与a作交换}   <BR>               if k&amp;lt; &amp;gt;i then   <BR>               begin   <BR>                  a:=a;<BR>                  a:=a;<BR>                  a:=a;   <BR>               end;   <BR>   end;   <BR>end;   </P>
<P>D. 冒泡排序   <BR>procedure sort;   <BR>var i,j,k:integer;   <BR>begin   <BR>    for i:=n downto 1 do   <BR>      for j:=1 to i-1 do   <BR>            if a &amp;gt;a then   <BR>            begin   <BR>               a:=a;<BR>               a:=a;<BR>               a:=a;   <BR>            end;   <BR>end;   </P>
<P>E.堆排序:   <BR>procedure sift(i,m:integer);{调整以i为根的子树成为堆,m为结点总数}   <BR>var k:integer;   <BR>begin   <BR>    a:=a; <BR>    k:=2*i;{在完全二*树中结点i的左孩子为2*i,右孩子为2*i+1}   <BR>    while k&amp;lt; =m do   <BR>    begin   <BR>      if (k&amp;lt; m) and (a&amp;lt; a) then inc(k);{找出a与a中较大值}   <BR>      if a&amp;lt; a then   <BR>      begin   <BR>         a:=a;<BR>         i:=k;<BR>         k:=2*i;   <BR>      end   <BR>      else <BR>         k:=m+1;   <BR>      end;   <BR>      a:=a; {将根放在合适的位置}   <BR>end; </P>
<P>procedure heapsort; <BR>var j:integer; <BR>begin   <BR>    for j:=n div 2 downto 1 do sift(j,n);   <BR>      for j:=n downto 2 do   <BR>      begin   <BR>            swap(a,a);   <BR>            sift(1,j-1);   <BR>      end; <BR>end; </P>
<P>F. 归并排序 <BR>{a为序列表,tmp为辅助数组} <BR>procedure merge(var a:listtype; p,q,r:integer); <BR>{将已排序好的子序列a与a合并为有序的tmp} <BR>var I,j,t:integer; <BR>    tmp:listtype; <BR>begin   <BR>    t:=p;<BR>    i:=p;<BR>    j:=q+1;{t为tmp指针,I,j分别为左右子序列的指针}   <BR>    while (t&amp;lt; =r) do   <BR>    begin   <BR>       if (i&amp;lt; =q){左序列有剩余} and ((j &amp;gt;r) or (a&amp;lt; =a)) then{满足取左边序列当前元素的要求}   <BR>       begin   <BR>          tmp:=a; inc(i);   <BR>       end   <BR>       else   <BR>       begin   <BR>          tmp:=a;<BR>          inc(j);   <BR>       end;   <BR>       inc(t);   <BR>    end;   <BR>    for i:=p to r do a:=tmp; <BR>end;{merge} </P>
<P>procedure merge_sort(var a:listtype; p,r: integer); {合并排序a} <BR>var q:integer; <BR>begin   <BR>    if p&amp;lt; &amp;gt;r then   <BR>    begin   <BR>       q:=(p+r-1) div 2;   <BR>       merge_sort (a,p,q);   <BR>       merge_sort (a,q+1,r);   <BR>       merge (a,p,q,r);   <BR>    end; <BR>end; <BR>{main} <BR>begin   <BR>    merge_sort(a,1,n); <BR>end. </P>

gghhjj 发表于 2005-8-28 14:57

回复:(ggggggl)[分享]一些基本算法

<P>9.树的遍历顺序转换   </P>
<P>A. 已知前序中序求后序   <BR>procedure Solve(pre,mid:string);   <BR>var i:integer;   <BR>begin   <BR>    if (pre='') or (mid='') then exit;   <BR>    i:=pos(pre,mid);   <BR>    solve(copy(pre,2,i),copy(mid,1,i-1));   <BR>    solve(copy(pre,i+1,length(pre)-i),copy(mid,i+1,length(mid)-i));   <BR>    post:=post+pre; {加上根,递归结束后post即为后序遍历}   <BR>end;   </P>
<P>B.已知中序后序求前序   <BR>procedure Solve(mid,post:string);   <BR>var i:integer;   <BR>begin   <BR>    if (mid='') or (post='') then exit;   <BR>    i:=pos(post,mid);   <BR>    pre:=pre+post; {加上根,递归结束后pre即为前序遍历}   <BR>    solve(copy(mid,1,I-1),copy(post,1,I-1));   <BR>    solve(copy(mid,I+1,length(mid)-I),copy(post,I,length(post)-i));   <BR>end;   </P>
<P>C.已知前序后序求中序   <BR>function ok(s1,s2:string):boolean;   <BR>var i,l:integer; <BR>    p:boolean;   <BR>begin   <BR>    ok:=true;   <BR>    l:=length(s1);   <BR>    for i:=1 to l do   <BR>    begin   <BR>      p:=false;   <BR>      for j:=1 to l do   <BR>      if s1=s2 then p:=true;   <BR>          if not p then   <BR>          begin   <BR>             ok:=false;exit;<BR>          end;   <BR>      end;   <BR>    end;   </P>
<P>procedure solve(pre,post:string);   <BR>var i:integer;   <BR>begin   <BR>    if (pre='') or (post='') then exit;   <BR>    i:=0;   <BR>    repeat   <BR>       inc(i);   <BR>    until ok(copy(pre,2,i),copy(post,1,i));   <BR>    solve(copy(pre,2,i),copy(post,1,i));   <BR>    midstr:=midstr+pre;   <BR>    solve(copy(pre,i+2,length(pre)-i-1),copy(post,i+1,length(post)-i-1));   <BR>end;   </P>
<P>10.求图的弱连通子图(DFS)   <BR>procedure dfs ( now,color: integer);   <BR>begin   <BR>    for i:=1 to n do   <BR>      if a and c=0 then   <BR>      begin   <BR>         c:=color;   <BR>         dfs(I,color);   <BR>      end;   <BR>end;   </P>
<P>12.进制转换   <BR>A.整数任意正整数进制间的互化   <BR>NOIP1996数制转换   <BR>设字符串A$的结构为: A$='mp'   <BR>其中m为数字串(长度&amp;lt; =20),而n,p均为1或2位的数字串(其中所表达的内容在2-10之间) <BR>程序要求:从键盘上读入A$后(不用正确性检查),将A$中的数字串m(n进制)以p进制的形式输出. <BR>例如:A$='48&amp;lt; 10 &amp;gt;8'   其意义为:将10进制数48,转换为8进制数输出.   <BR>输出结果:48&amp;lt; 10 &amp;gt;=60&amp;lt; 8 &amp;gt;   <BR>B.实数任意正整数进制间的互化   <BR>C.负数进制:   NOIP2000   设计一个程序,读入一个十进制数的基数和一个负进制数的基数,<BR>并将此十进制数转换为此负 进制下的数:-R∈{-2,-3,-4,....-20}             </P>
<P>13.全排列与组合的生成   排列的生成:(1..n)   <BR>procedure solve(dep:integer);   <BR>var   i:integer;   <BR>begin   <BR>      if dep=n+1 then <BR>      begin <BR>         writeln(s);<BR>         exit; <BR>      end;   <BR>      for i:=1 to n do   <BR>         if not used then   <BR>         begin   <BR>            s:=s+chr(i+ord('0'));<BR>            used:=true;   <BR>            solve(dep+1);   <BR>            s:=copy(s,1,length(s)-1); <BR>            used:=false;   <BR>         end;   <BR>end;   </P>
<P>组合的生成(1..n中选取k个数的所有方案)   <BR>procedure solve(dep,pre:integer);   <BR>var   i:integer;   <BR>begin   <BR>      if dep=k+1 then <BR>      begin <BR>         writeln(s);<BR>         exit; <BR>      end;   <BR>      for i:=1 to n do   <BR>         if (not used) and (i &amp;gt;pre) then   <BR>         begin   <BR>             s:=s+chr(i+ord('0'));<BR>             used:=true;   <BR>             solve(dep+1,i);   <BR>             s:=copy(s,1,length(s)-1); <BR>             used:=false;   <BR>         end;   <BR>end;         </P>

gghhjj 发表于 2005-8-28 14:57

回复:(ggggggl)[分享]一些基本算法

<P>14 递推关系   计算字串序号模型   USACO1.2.5 StringSobits   <BR>长度为N (N&amp;lt; =31)的01串中1的个数小于等于L的串组成的集合中找出按大小排序后的第I个01串。<BR>数字划分模型 <BR>*NOIP2001数的划分 <BR>将整数n分成k份,且每份不能为空,<BR>任意两种分法不能相同(不考虑顺序)。 <BR>d:=1; <BR>for p:=1 to n do <BR>    for i:=p to n do <BR>       for j:=k downto 1 do inc(d,d); <BR>         writeln(d); <BR>*变形1:考虑顺序 <BR>d[ i, j] : = d [ i-k, j-1] (k=1..i) <BR>*变形2:若分解出来的每个数均有一个上限m <BR>d[ i, j] : = d [ i-k, j-1] (k=1..m) </P>
<P>15.算符优先法求解表达式求值问题 <BR>const maxn=50; <BR>var s1:array of integer; {s1为数字栈} <BR>    s2:array of char; {s2为算符栈} <BR>    t1,t2:integer; {栈顶指针} <BR>procedure calcu; <BR>var x1,x2,x:integer; <BR>    p:char;<BR>begin   <BR>    p:=s2; <BR>    dec(t2);   <BR>    x2:=s1; <BR>    dec(t1);   <BR>    x1:=s1; <BR>    dec(t1);   <BR>    case p of   <BR>      '+':x:=x1+x2;   <BR>      '-':x:=x1-x2;   <BR>      '*':x:=x1*x2;   <BR>      '/':x:=x1 div 2;   <BR>    end;   <BR>    inc(t1);<BR>    s1:=x; <BR>end; <BR>procedure work; <BR>var c:char;<BR>    v:integer; <BR>begin   <BR>    t1:=0;<BR>    t2:=0;   <BR>    read(c);   <BR>    while c&amp;lt; &amp;gt;';' do   <BR>       case c of<BR>       '+','-':   <BR>       begin   <BR>         while (t2 &amp;gt;0) and (s2&amp;lt; &amp;gt;'(') do calcu;   <BR>               inc(t2);s2:=c;   <BR>               read(c);   <BR>       end ;   <BR>       '*','/':<BR>       begin   <BR>         if (t2 &amp;gt;0) and ((s2='*') or (s2='/')) then calcu;   <BR>         inc(t2);s2:=c;   <BR>         read(c);   <BR>       end;   <BR>       '(':<BR>       begin <BR>         inc(t2); <BR>         s2:=c; <BR>         read(c); <BR>       end;   <BR>       ')':<BR>       begin   <BR>         while s2&amp;lt; &amp;gt;<BR>       '(' do calcu;   <BR>         dec(t2); <BR>         read(c);   <BR>       end;   <BR>       '0'..'9':<BR>       begin   <BR>         v:=0;   <BR>         repeat   <BR>            v:=10*v+ord(c)-ord('0');   <BR>            read(c);   <BR>         until (c&amp;lt; '0') or (c &amp;gt;'9');   <BR>         inc(t1); <BR>         s1:=v;   <BR>       end;   <BR>      end;   <BR>      while t2 &amp;gt;0 do calcu;   <BR>         writeln(s1); <BR>end; </P>
<P>16.查找算法   <BR>折半查找   <BR>function binsearch(k:keytype):integer;   <BR>var low,hig,mid:integer;   <BR>begin   <BR>    low:=1;<BR>    hig:=n;   <BR>    mid:=(low+hig) div 2;   <BR>    while (a.key&amp;lt; &amp;gt;k) and (low&amp;lt; =hig) do<BR>    begin   <BR>         if a.key &amp;gt;k then hig:=mid-1   <BR>         else low:=mid+1;   <BR>            mid:=(low+hig) div 2;   <BR>         end;   <BR>         if low &amp;gt;hig then mid:=0;   <BR>            binsearch:=mid;   <BR>end;   <BR>树形查找   <BR>二*排序树:每个结点的值都大于其左子树任一结点的值而小于其右子树任一结点的值。   <BR>查找   <BR>function treesrh(k:keytype):pointer;   <BR>var q:pointer;   <BR>begin   <BR>    q:=root;   <BR>    while (q&amp;lt; &amp;gt;nil) and (q^.key&amp;lt; &amp;gt;k) do   if k&amp;lt; <BR>       q^.key then q:=q^.left   else q:=q^.right;   <BR>    treesrh:=q;   <BR>end;</P>

linqus 发表于 2005-8-28 15:23

不知楼主用的是什么代码,<BR>vb/ada?还是伪代码?<BR>只用过fortran,c及matlab语言。<BR>

christy 发表于 2005-8-28 20:55

回复:(ggggggl)[分享]一些基本算法

<P>怎么看这像是脚本程序?</P>

FSI 发表于 2005-8-29 09:27

<P>像是pascal。呵呵 能看明白就行了,反正讲的是算法原理。</P>

Xavier_kai 发表于 2005-10-9 23:30

谢谢 楼主

Frigoris 发表于 2006-4-22 18:54

好东西啊,全面总结<BR>好像的确是Pascal,不过我已经忘光了pascal<BR>现在Pascal对我来说就等于一种伪代码:P
页: [1]
查看完整版本: [分享]一些基本算法