PKU1011 Sticks
2010-06-05 21:29
190 查看
这是一道比较经典的搜索题目,运用到了深度优先搜索。
首先,我们显然要先对题目中的n个数据所在数组a进行排序。
接着,我们进行题目的分析。我们要求最小的可能木棒长度,于是就从小到大枚举这一长度。显然长度len的下限为n个数据中最长的小木棒的长度;上限是所有n个数据长度总和。另外我们还要开一个sum数组,用于记录当前长度为i的小木棒剩余的个数,也相当于通常所用的vis数组。此外,我们使用b数组记录所有的不同长度,便于我们快速地进行选择可用小木棒长度。
以上的操作均是运用空间换时间的思想,降低了搜索过程中的常数大小。但想要在时间限制内通过所有测试数据,高效的搜索技巧势在必行。
先考虑一下搜索顺序——对于数组a中的小木棒我们是要递增搜索还是递减搜索。只要想象一棵搜索树就能发现,如果采用递减搜索可以避免重复搜索,减少搜索量,利于提高稍后剪枝的效率。
再想想这道题目本身——如果有这么一段小木棒,将它放到已经积累了一部分的初始木棒后恰好填满长度len,那么我们就是用它。因为没有其他的组合比这个小木棒更有可能得到正解了。
此外如果在确定一个初始木棒的组成时,搜索当前可用最长小木棒时发现要回溯到更小的木棒,那就exit剪掉它。原因显而易见——如果当前不用这个最长小木棒,那么以后也必须要用到,且还会得不到正解而回溯。所以这种情况时一定要剪枝的,而且这个剪枝的高效性不言而喻,它就是这道题的题眼!
这样这道题目我们就完美地解决了!
首先,我们显然要先对题目中的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.
相关文章推荐
- PKU1011 Sticks 经典DFS(TLE了。。没办法)
- pku-1011-Sticks
- pku 1011 sticks
- pku 1011 sticks 经典DFS+剪枝
- pku 1011 sticks 搜索+剪枝 解题报告
- pku 1011 sticks
- ACM PKU 1011 Sticks 深度优先搜索
- PKU 1011 Sticks
- PKU-1011 Sticks (DFS + 剪枝)
- PKU 1011 Sticks
- 搜索剪枝回溯经典题目 pku 1011 sticks
- PKU 1011 Sticks
- ACM poj 1011 Sticks解题报告源代码【转】
- POJ1011 Sticks
- poj 1011 Sticks
- poj 1011 Sticks(dfs+剪枝)
- poj 1011 Sticks【dfs】
- poj 1011 Sticks 减枝搜索
- POJ 1011 Sticks
- poj1011 Sticks(dfs+剪枝)