您的位置:首页 > 其它

PKU1011 Sticks

2010-06-05 21:29 190 查看
这是一道比较经典的搜索题目,运用到了深度优先搜索。
首先,我们显然要先对题目中的n个数据所在数组a进行排序。
接着,我们进行题目的分析。我们要求最小的可能木棒长度,于是就从小到大枚举这一长度。显然长度len的下限为n个数据中最长的小木棒的长度;上限是所有n个数据长度总和。另外我们还要开一个sum数组,用于记录当前长度为i的小木棒剩余的个数,也相当于通常所用的vis数组。此外,我们使用b数组记录所有的不同长度,便于我们快速地进行选择可用小木棒长度。
以上的操作均是运用空间换时间的思想,降低了搜索过程中的常数大小。但想要在时间限制内通过所有测试数据,高效的搜索技巧势在必行。
先考虑一下搜索顺序——对于数组a中的小木棒我们是要递增搜索还是递减搜索。只要想象一棵搜索树就能发现,如果采用递减搜索可以避免重复搜索,减少搜索量,利于提高稍后剪枝的效率。
再想想这道题目本身——如果有这么一段小木棒,将它放到已经积累了一部分的初始木棒后恰好填满长度len,那么我们就是用它。因为没有其他的组合比这个小木棒更有可能得到正解了。
此外如果在确定一个初始木棒的组成时,搜索当前可用最长小木棒时发现要回溯到更小的木棒,那就exit剪掉它。原因显而易见——如果当前不用这个最长小木棒,那么以后也必须要用到,且还会得不到正解而回溯。所以这种情况时一定要剪枝的,而且这个剪枝的高效性不言而喻,它就是这道题的题眼!
这样这道题目我们就完美地解决了!
program sticks;
var
a,b,sum:array[0..64] of longint;
n,i,j,k,min,len,tot,all,p,q:longint;
flag:boolean;
procedure dfs(dep,tmp:longint);
var
p,i:longint;
begin
if dep>all then
begin
flag:=true;
exit;
end;
p:=len-tmp;
if (p<=min) and (sum[p]>0) then
begin
dec(sum[p]);
dfs(dep+1,0);
inc(sum[p]);
exit;
end;
for i:=k downto 1 do
if (sum[b[i]]>0) and (b[i]<=p) then
begin
dec(sum[b[i]]);
dfs(dep,tmp+b[i]);
inc(sum[b[i]]);
if flag or (tmp=0) then
exit;
end;
end;
begin
assign(input,'a.in');
reset(input);
assign(output,'a.out');
rewrite(output);
readln(n);
while n<>0 do
begin
min:=0;
tot:=0;
fillchar(sum,sizeof(sum),0);
flag:=false;
for i:=1 to n do
begin
read(k);
inc(sum[k]);
a[i]:=k;
inc(tot,k);
if k>min then
min:=k;
end;
for i:=1 to n-1 do
for j:=i+1 to n do
if a[i]>a[j] then
begin
k:=a[i];
a[i]:=a[j];
a[j]:=k;
end;
p:=1;
q:=1;
k:=0;
while p<=n do
begin
while (q+1<=n) and (a[q+1]=a[p]) do
inc(q);
inc(k);
b[k]:=a[p];
p:=q+1;
end;
for len:=min to tot do
if tot mod len=0 then
begin
all:=tot div len;
dfs(1,0);
if flag then
begin
writeln(len);
break;
end;
end;
readln(n);
end;
close(input);
close(output);
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: