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]
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
if l
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]
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.