算法教程3

第二章  算法应用
一、穷举搜索法
    穷举搜索法是穷举所有可能情形,并从中找出符合要求的解。
    穷举所有可能情形,最直观的是联系循环的算法。
    [例]找出n个自然数(1,2,3,…,n)中r个数的组合。例如,当n=5,r=3时,所有组合为:
          5      4      3
          5      4      2
          5      4      1
          5      3      2
          5      3      1
          5      2      1
          4      3      2
          4      3      1
          4      2      1
          3      2      1
           total=10     {组合的总数}
    [解]n个数中r的组合,其中每r 个数中,数不能相同。另外,任何两组组合的数,所包含的数也不应相同。例如,5、4、3与3、4、5。为此,约定前一个数应大于后一个数。
    将上述两条不允许为条件,当r=3时,可用三重循环进行搜索。
    [程序]
      Program  zuhe11;
      const n=5;
      var  i,j,k,t:integer;
      begin  t:=0;
        for  i:=n  downto  1  do
          for  j:=n  downto  1  do
            for  k:=n  downto  1  do
              if (i<>j)and(i<>k)and(i>j)and(j>k) then
                begin t:=t+1;writeln(i:3,j:3,k:3);end;
        writeln(';total=';,t);
      end.
    或者
      Program  zuhe12;
      const n=5;r=3;
      var  i,j,k,t:integer;
      begin  t:=0;
        for  i:=n  downto  r  do
          for  j:=i-1  downto  r-1  do
            for  k:=j-1  downto  1  do
                begin t:=t+1;writeln(i:3,j:3,k:3);end;
        writeln(';total=';,t);
      end.
    这两个程序,前者穷举了所有可能情形,从中选出符合条件的解,而后者比较简洁。但是这两个程序都有一个问题,当r变化时,循环重数改变,这就影响了这一问题的解,即没有一般性。
    但是,很多情况下穷举搜索法还是常用的。 

二、递归法
    递归法也是常用的方法。
   [例]仍以前节例题为例,找n个数的r个数的组合。要求:
    输入:n,r=5  3
    输出:5      4      3
          5      4      2
          5      4      1
          5      3      2
          5      3      1
          5      2      1
          4      3      2
          4      3      1
          4      2      1
          3      2      1
           total=10     {组合的总数}
    [解]分析所提示的10组数。首先固定第一位数(如5),其后是在另4个数中再“组合”2个数。这就将“5个数中3个数的组合”推到了“4个数中2个数的组合”上去了。第一位数可以是n    r(如5    3),n个数中r个数组合递推到n-1个数中r-1个数有组合,这是一个递归的算法。即:
    Procedure   comb(n,r:integer);
    var  i:integer;
    begin  for  i:=n  downto  r  do
      begin  {固定i的输出位置}
        comb(i-1,r-1);  {原过程递推到i-1个数的r-1个数组合}
      end;
    end;
    再考虑打印输出格式。
    [程序]
    Program  zuhe2;
    var  k,n,r:integer;
    Produrce   comb(n,r:integer);
    var  i,temp:integer;
    begin  for  i:=n  downto  r  do
      if  (i<>n)and(k<>r)  then    {k为过程外定义的}
        begin for temp:=1 to  (k-r)*3  do  write(';  ';); {确定i的输出位置}
        end;
      write(i:3);
      if i>1 then comb(i-1,r-1);  {递推到下一情形}
      else writeln;
    end;
    Begin {main}
     write(';n,r=';);readln(n,r);
     if  r>n  then
       begin  writeln(';Input n,r error!';);halt; end;
     comb(n,r);  {调用递归过程}
   End;
三、回溯法
     回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
    [例]再以前例说明,找n个数中r个数的组合。
    [解]将自然数排列在数组A中:
      A[1]    A[2]    A[3]
       5       4       3
       5       4       2
          …
       3       2       1
    排数时从A[1]    A[2]     A[3],后一个至少比前一个数小1,并且应满足ri+A[ri]>r。若ri+A[ri]≤r就要回溯,该关系就是回溯条件。为直观起见,当输出一组组合数后,若最后一位为1,也应作一次回溯(若不回,便由上述回溯条件处理)。
    [程序]
     program  zuhe3;
     type  tp=array[1..100] of integer;
     var  n,r:integer;
     procedure  comb2(n,r:integer;a:tp);
     var  i,ri:integer;
     begin  ri:=1;a[1]:=n;
       repeat  
        if  ri<>r  then   {没有搜索到底}
          if  ri+a[ri]>r  then    {是否回溯}
            begin  a[ri+1]:=a[ri]-1;
              ri:=ri+1;
            end
          else
            begin  ri:=ri-1; a[ri]:=a[ri]-1;end; {回溯}
        else
          begin  for j:=1 to r do write(a[j]:3);writeln; {输出组合数}
            if  a[r]=1  then  {是否回溯}
              begin  ri:=ri-1; a[ri]:=a[ri]-1;end; {回溯}
            else  a[ri]:=a[ri]-1;  {递推到下一个数}
          end;
       until  a[1]<>r-1;
     end;
     begin {MAIN}
       write(';n,r=';);readln(n,r);
       if  r>n  then
         begin  writeln(';Input n,r error!';);halt; end
       comb2(n,r);
     end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值