算法教程5

来源:互联网 发布:js的onload事件怎么用 编辑:程序博客网 时间:2024/05/14 03:46
综合测试题(二)
1、回文问题:递归法判断所输入的一行字符是否回文。这里所说的回文是指输入的一行字符,
以“-”字符为中心,其两边的字符是左右对称的。例如:
    输入:ABCDE-EDCBA ↓
    输出:It is symmetry.  {输入一行字符是回文}
    [解]设一行字符为M-W,对于M分解成由ch1表记的一个字符与一子串m;对w分解成一字符子串w和由ch2表记的一个字符,因此M-W这“回文”取决于:(1)m-w是回文;(2)ch1-ch2。即将原问题递推到m-w的解。递归终止条件是M与W(或m与w)长度为0。“回归”时,若m-w是回文且ch1=ch2,则M-W是回文;否则M-W就不是回文。程序使用递归过程pp。
    [程序]

[Copy to clipboard] [ - ]
CODE:
    PROGRAM MW;
    var ch:char;
    function pp:boolean;
    var ch1,ch2:char; bl:boolean;
    begin read(ch1);
      if ch1=';-'; then bl:=true
      else begin
if pp then begin read(ch2);bl:=ch1=ch2;end
        else bl:=false;
      end;
      pp:=bl;
  end;
    begin {MAIN}
      write(';Input string:';);
      if pp then begin read(ch);
        if ord(ch)=13 then begin writeln;writeln(';It is symmetry.';);end
        else begin writeln;writeln(';It is not symmetry.';);end;
      end
    else begin writeln;writeln(';It is not symmetry.';);end
  end.

2、三齿轮问题:三个齿轮啮合。如图在齿轮箱里
    三个齿轮互相衔接,某瞬间两对齿相遇,问各转
    多少圈后,这两对齿同时重逢。如图示。
    (说明:用a,b,c分别表示三个齿轮的齿数。)
    [解]这一问题是最小公倍数问题。设三齿轮齿数分别是na、nb、nc,[na,nb,nc]为最小公倍数,相遇各齿轮所转的圈数为最小公倍数除以自己的齿数。
    [程序]
     {$I-}

[Copy to clipboard] [ - ]
CODE:
     program cl;
     var na,nb,nc,ma,mb,mc,l3:integer;
     
     function gcd(x,y:integer):integer; { 求最大公约数函数 }
     var r:integer;
     begin
       repeat r:=x mod y;x:=y;y:=r;until r=0;
       gcd:=x;
     end;
     function lcm(x,y:integer):integer; { 求最小公倍数函数 }
     begin lcm:=(x*y div gcd(x,y));
     end;
     function lcm3(a1,a2,a3:integer):integer; { 求三个数的最小公倍数函数 }
     begin lcm3:=lcm(lcm(a1,a2),a3); end;
     begin {main}
       write(';na,nb,nc=';);readln(na,nb,nc); 读入三齿轮齿数
       if (na<1)or(nb<1)or(nc<1) then begin writeln(';Input error!';);exit;end;
       l3:=lcm3(na,nb,nc); {求na,nb,nc的最小公倍数}
       ma:=l3 div na; {求各齿轮所转的圈数}
       mb:=l3 div nb; mc:=l3 div nc;
       writeln(';For mesh must rotate about rings:';,ma:3,mb:3,mc:3);
     end.

3、计算合数:一个整数n(n<=100)可以有多种分划,使其分划的一列整数之和为n。例如:
    输入:n=6
    输出文件hs.out,格式内容为
     6
     5  1
     4  2
     4  1  1
     3  3
     3  2  1
     3  1  1  1
     2  2  2
     2  2  1  1
     2  1  1  1
     1  1  1  1  1  1
     total=11   {表示分划数有11种}
    [解]采用递归算法。从最大合数开始分划,若当前分划数之和仍不大于n,则继续分解。否则回溯再寻找分划。
    [程序]
    {$S-}

[Copy to clipboard] [ - ]
CODE:
    program hs;
    var  i,j,m,k,t:integer;
      n:array[0..100] of integer;
      f:text;
    procedure output_sum;
    var j:integer;
    begin t:=t+1;j:=0;
      while n[j]<>0 do {输出所有不为的合数}
        begin write(f,n[j]:3);j:=j+1;end;
      writeln(f);
    end;
    procedure sum(i:integer);
    begin
      if m-n[i]<=n[i] then {整数分解后的余数不大于已分解的合数}
        begin n[i+1]:=m-n[i];m:=m-n[i]; i:=i+1;n[i+1]:=0; end
      else {整数分解后的余数大于已分解的合数}
        begin n[i+1]:=n[i];m:=m-n[i];i:=i+1;end;
      if m<>n[i] then sum(i) {未分解完继续分解}
      else output_sum;   {输出合数}
      if n[i]>1 then {若合数大于1可继续分解,否则回溯寻找大于1的合数}
        begin n[i]:=n[i]-1;sum(i);end
      else
        begin while (n[i]=1)and(i>0) do
          begin i:=i-1;m:=m+n[i];end;
            if i<>0 then {找到大于1的合数,则继续分解}
              begin n[i]:=n[i]-1;sum(i);end;
        end;
    end;
  begin {MAIN}
    assign(f,';hs.out';);rewrite(f);
    write(';Input a number:';);readln(n[0]);
    t:=0;m:=n[0];k:=n[0]; {第1个合数设为要分解的数}
    for i:=1 to k do
      n[i]:=0; {除第1个合数外所有合数初值均为0}
    output_sum; {输出第1次分解的合数}
    while n[0]<>1 do {第1个合数不为1,则继续分解寻找合数}
      begin n[0]:=n[0]-1;i:=0;
        sum(0); m:=k;
      end;
    writeln(f,';total=';,t); close(f)
  end.

4、旅行路线选择:设有n个城市(或景点),今从某市出发遍历各城市,使之旅费最少(即找出一条旅费最少的路径)。
    输入部分:各城市间的旅费表由输入文件提供。
    输出部分:旅费最少的一条路径及总费用。
    例如:
    输入文件名:ex14501.dat
    输出文件名:1.out
    其中,输入文件ex14501.dat的内容如下:
        0    17    13     24   10
        10     0    20     9     6
        17    29     0    21    28
        12    10    22     0    19
        12    18    31    20     0   
    输出文件1.out的内容如下:
        The route path is:0->2->3->1->4->0  {最少旅费城市路径}
        Total of traveling expense: 62       {最少旅费数}
    [解]设矩阵元素aij 表示从第i号城市到第j号城市之旅费。并设城市间往返旅费可以不等(即aij ≠aji )。aii 是没有意义的,由于问题是求最少,因此aii 不应为零,今试为无穷(∞)。各城市间旅费如下表:
        ∞   17  13  24  10  
        10  ∞  20   9   6  
        17  29  ∞  21  28  
        12  10  22  ∞  19  
        12  18  31  20  ∞  
     问题的算法是在表每行中找最小元素,并用该数减该行非∞元素。再对每列也施同样工作,形成一个新表(保证每行、每列均不少于1个为零),所有减数累加为min(其含义为旅费下界,即旅费不会少于min)。旅行路程因成环路,故可设起点是第0号城市。若选第i号到第j号城市,则表上bij 表示还需旅费,同时由于选了i→j,则i不可能再选向其它城市,则第i行全填∞,同理,由于j已由i过来,则第j城市不可能再由其它城市过来,第j列也全填上∞。对新矩阵再施每行至少有一个0,每列至少有一个0,找出余下城市遍历所需旅费下界mj 。对于不同的j,比较mj +bij 以最小的一个为选定从i到达的城市,并将选择路径记下。如此重复直到选完。下列表表示了分枝选择和每次选择的旅费下界。
    初始表:    min=61
        *    7    0    11    0
        4    *   11     0    0
        0   12    *     1   11
        2    0    9     *    9
        0    6   16     5    *

    从0号城市出发的4种可能:        
        0→1    min=9                            0→2    min=0
        *    *    *     *    *                   *    *    *     *    *   
        4    *    4     0    0                   4    *    4     0    0   
        0    *    *     1   11                   0    *    *     1   11   
        0    *    0     *    7                   0    *    0     *    7   
        0    *    9     5    *                   0    *    9     5    *   
        0→3    min=9                            0→2    min=0
        *    *    *     *    *                   *    *    *     *    *   
        4    *    2     *    0                   4    *    2     0    *   
        0   12    *     *   11                   0   12    *     1    *   
        0    0    0     *    9                   2    0    0     *    *   
        0    6    7     *    *                   0    6    7     5    *   
    从中选择应是0→2。再从2出发,有3种选择:
        2→1    min=2             2→3    min=0              2→4    min=0         
        *    *    *     *    *    *    *    *     *    *     *    *    *     *    *
        4    *    *     0    0    4    *    *     *    0     4    *    *     *    *
        *    *    *     *    *    *    *    *     *    *     0    *    *     *    *
        0    *    *     *    7    2    0    *     *    9     2    0    *     *    *
        0    *    *     5    *    0    6    *     *    *     0    6    *     *    *
    从中应选2→3。再从3出发,2种选择:
        3→1    min=0                        3→4    min=10
        *    *    *     *    *               *    *    *     *    *   
        4    *    *     *    0               0    *    *     *    *   
        *    *    *     *    *               *    *    *     *    *   
        *    *    *     *    *               *    *    *     *    *   
        0    *    *     *    *               0    0    *     *    *   
    从中选3→1。再从2出发可选:
                  1→4    min=0               
                  *    *    *     *    *      
                  *    *    *     *    *      
                  *    *    *     *    *      
                  *    *    *     *    *      
                  0    *    *     *    *      
    [程序]

[Copy to clipboard] [ - ]
CODE:
    program mm;
    uses crt;
    const n=5;
      max=1000;
    type tp=array[0..n,0..n] of integer;
    var  f1,f2:text; fn1,fn2:string;
      i,j,k,min,m1,m,jj,kk,si,sj:integer;
      a,b,c,d:tp;
      path,s:array[0..n] of integer;
    procedure p(var b:tp;var m:integer);
    var pi,pj,pk:integer;
      px,py:integer;
    begin m:=0;
      for pi:=0 to n-1 do
        begin pk:=max;
          for pj:=0 to n-1 do
            if b[pi,pj]<pk then  pk:=b[pi,pj];
          if (pk>0)and(pk<>max) then
            begin m:=m+pk;
              for pj:=0 to n-1 do
                if b[pi,pj]<>max then
                  b[pi,pj]:=b[pi,pj]-pk;
            end;
        end;
        for pj:=0 to n-1 do
          begin pk:=max;
            for pi:=0 to n-1 do
              if b[pi,pj]<pk then pk:=b[pi,pj];
              if (pk>0)and(pk<>max) then
                begin m:=m+pk;
                  for pi:=0 to n-1 do
                    if b[pi,pj]<>max then
                      b[pi,pj]:=b[pi,pj]-pk;
                end;
          end;
    end;
    begin {MAIN}
      clrscr;write(';Input filename:';);readln(fn1);
      write(';Output filename:';);readln(fn2);
      assign(f1,fn1);reset(f1);assign(f2,fn2);rewrite(f2);
      writeln(f2,';Traveling expenses table:';);
      for i:=0 to n-1 do {读城市旅费表}
        begin for j:=0 to n-1 do
          begin read(f1,a[i,j]);write(f2,a[i,j]:6);end;
          writeln(f2);
        end;
      for i:=0 to n-1 do a[i,i]:=max; {aii无意义的,设为max}
      k:=0;path[0]:=0;i:=0;s[0]:=max; {从0号城市出发}
      for j:=1 to n-1 do s[j]:=0;  {s[j]为0时表示未到达j号城市,否则已走过}
      for si:=0 to n-1 do  {矩阵转置}
        for sj:=0 to n-1 do
          b[si,sj]:=a[si,sj];
      p(b,min);  {调用函数,计算旅费下界及最低旅费}
      repeat
        m1:=max;
        for j:=0 to n-1 do
          if (s[j]=0)and(b[i,j]<>max) then 可到达的城市却未遍历
            begin
              for si:=0 to n-1 do
                for sj:=0 to n-1 do
                  c[si,sj]:=b[si,sj]; {矩阵转置}
              for kk:=0 to n-1 do {从i城市出发已不可能,从其他城市到j城市也不可能}
                begin c[i,kk]:=max;c[kk,j]:=max; end;
              p(c,m); {调用函数,计算从i到j城市的旅费下界}
             if m+b[i,j]<m1 then {求最小旅费路径}
               begin m1:=m+b[i,j];jj:=j;
                 for si:=0 to n-1 do
                   for sj:=0 to n-1 do
                     d[si,sj]:=c[si,sj];  {保存最小旅费表}
               end;
           end;
       for si:=0 to n-1 do
         for sj:=0 to n-1 do
           b[si,sj]:=d[si,sj]; {将所选择的最小旅费表存入初始表}
        min:=min+m1;i:=jj; {jj号城市作为出发点}
        k:=k+1;path[k]:=jj;
        s[jj]:=max;sj:=max;
        for si:=0 to n-1 do {判断所有城市是否都已到达}
        if s[si]<>max then sj:=0;
      until sj=max; {直至所有城市都已走过为止}
      write(f2,';The route path is:';);
      for i:=0 to k do write(f2,path[i],';->';);
      writeln(f2,';0';);
      writeln(f2,';Total of traveling expense:';,min:5);
      close(f1);close(f2);
    end. 
原创粉丝点击