解题报告 poj 1011 木棒

 

1.        题目 poj 1011

Description

乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。

Input

输入包含多组数据,每组数据包括两行。第一行是一个不超过64的整数,表示砍断之后共有多少节木棍。第二行是截断以后,所得到的各节木棍的长度。在最后一组数据之后,是一个零。

Output

为每组数据,分别输出原始木棒的可能最小长度,每组数据占一行。

Sample Input

9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0

Sample Output

6
5

Source

Central Europe 1995

Translator

北京大学程序设计实习, Xie Di

 

2.        题目实质

超级 BT 无敌充斥着剪枝的搜索。

3.        题目来源 poj

4.        算法

框架的搜索就不说了,他的剪枝主要有三个:

1.      当前这个棍子有没有用过。

2.      当他大于所需要搜的长度时,就不用搜了。

3.      如果前面一个相等长度的棍子用不上,那么这个棍子自然也用不上。

然后还有一些小剪枝:

4.      预处理排序后方便以后搜。

5.      从大到小搜,不重复搜。

6.      搜的长度一定要整除总长度,而且大于最长的那一根棍子。

7.      从当前最长的未被使用的木棍开始搜。

8.      设置递归层数。

9.      搜索总长度的一半到总长度之间的也无意义。

然后,去写吧……

5.        注意事项

就是以上这一批剪枝。

6.        程序代码

Loong854  Pascal

var

  i,j,k,n,m,sum,max:Longint;

  a:array[0..100] of longint;

  v:array[0..100] of boolean;

  z:array[0..1000] of longint;

  flag,flag1:boolean;

procedure init;

  begin

    sum:=0;

    for i:=1 to n do

      begin

        read(a[i]);

        inc(sum,a[i]);

      end;

  end;

procedure  fast(l,r:longint);//排序也算是一个优化吧

  var

    i,j,t:longint;

    tmp:longint;

  begin

    randomize;

    i:=l;

    j:=r;

    t:=a[random(r-l+1)+l];

    repeat

      while a[i]<t do inc(i);

      while a[j]>t do dec(j);

      if i<=j then

        begin

          tmp:=a[i];

          a[i]:=a[j];

          a[j]:=tmp;

          inc(i);

          dec(j);

        end;

      until i>j;

      if i<r then fast(i,r);

      if l<j then fast(l,j);

  end;

 

procedure  dfs(kk,l:longint;t:longint);//第二个优化:t记录从第几个开始搜,省去了一些循环;

  var

    ii,jj:Longint;

  begin

    if not flag then exit;

    if (kk=0) and (l=i) then

      begin

        writeln(i);

        flag:=false;

        exit;

        halt;

      end;

      jj:=100;//递归循环第一个时,即使和前一个相同,也可以装

    for ii:=t downto 1 do

      if v[ii] and (a[ii]<>a[jj]) then//第三个优化:比较强大的,若一个包装了一个木棍没有搜到可行解,再装相同的木棍也不会搜到(因为木棍长度是有序的,只需记录前一个木棍的长度即可)

          begin

          jj:=ii;

          if a[ii]<l then

            begin

              v[ii]:=false;

              dfs(kk,l-a[ii],ii);

              if not flag then exit;

              v[ii]:=true;

              if l=i then exit;//第四个优化也是最强大的:如果每个包装了第一个没有搜到可行解,装其他的也不可行,直接退出,重新装前一个包

            end

            else

            if a[ii]=l then

              begin

                v[ii]:=false;

                dfs(kk-1,i,n-1);

                if not flag then exit;

                v[ii]:=true;

                exit;

              end;

 

        end;

  end;

procedure  main;

  begin

    fast(1,n);

    flag:=true;

    fillchar(v,sizeof(v),true);

    for i:=a[n] to (sum div 2) do

      begin

        if sum mod i<>0 then continue;//优化五:最简单的,所求木棍长度一定是总长度的约数

        k:=sum div i;

        if i=a[n] then dfs(k-2,i,n-1)

          else dfs(k-1,i-a[n],n-1);

        if not flag then exit;

      end;

    writeln(sum);

  end;

begin

  assign(input,'loongau.in');reset(input);

  assign(output,'loongau.out');rewrite(output);

  readln(n);

  while n<>0 do

    begin

      init;

      main;

      readln(n);

    end;

  close(input);

  close(output);

end.

 

原文地址:https://www.cnblogs.com/SueMiller/p/2136377.html