POJ1011
今天搞了一下传说中的经典搜索题——poj1011,果然里面充斥着各种巧妙的剪枝,做完之后回味一下还是感觉构思太巧妙,所以总结记录一下加深理解。
原题:http://poj.org/problem?id=1011
刚开始接触搜索的初学者面对这道题可能感觉无从下手,即便是告诉了要用深搜解决这道题,也不知道怎么用,我现在也对搜索有了更多的理解与体会,其实不要把搜索只理解为在一个地图上找点,其实搜索更可以抽象为当面对多个选择的时候如何抉择,深搜就是先认准一个方向走下去,不行再回来,走别的路;广搜就是把每一次能做的选择都试一遍。所以,这道拼木棍的题就是一道很好的深搜题。我们不知道哪根木棍可组合进来,那不如就按从前往后的顺序一个一个试。
唠叨了半天,终于该放代码了。。简单的注释我写在程序里了,稍微长一点的解释,我程序里有序号,我把详细的解释写在外面,大家对一下序号来看。
PS:我不能确定我写的已经是优化到最好了,也希望有更好想法的小伙伴可以在评论里教下我,谢谢~如果喜欢别忘了点赞哟~
- 这里要解释的是sticks[i]!=pre,假设有几根木棍是5 5 5 2,这时,若确定第一根已经不满足条件了,后面两根长度为5的木棍也没有必要去试了,所以跳过就好了。这里可能会有小伙伴理解为这样会导致不能正确的加入两根相同的木棍(我最初就这样想的。。),比如5 2 5 1 1,会理解为最后一个1加不上了。其实当第一个1符合条件的情况下,函数会再次调用,所以新调用的函数了pre又是0了,所以这个条件完美排除了第一根就不符合条件的情况,并没有影响重复长度木棍第一根符合要求的情况。
- 这里dfs的返回值若为1,说明已经完成题目要求了(前面只有cnt==num才返回1),所以可以跳出循环,这会影响后面if语句的判断,若是跳出的,说明找到了,若不是跳出,正常结束循环,说明没有找到。
- 这个剪枝也很巧妙,它是考虑了,当我每合并一个新木棍时,第一根木棍是很特殊的,我们每次从前往后挑选木棍时,总是选没用过且长度符合要求的,这也就意味着,当我们选中了第一根木棍时,它的长度是符合要求的,这一根是一定要用的(无论对于哪个合成的木棍,这根都会是作为第一根用,这里大家好好琢磨一下),所以若前面的if语句没执行,就会执行这一句,而且满足k==0,说明后面的木棍都没法和这第一根木棍组成新木棍了,所以可以直接退出了(尽量解释了,大家好好想下)
#include<stdio.h>
#include<string.h>
int sticks[],book[];//一个存木棍,一个标记是否使用
int n,len,num;//len是合并后每根木棍的长度,num是合并后的木棍数目
//手写快排,不太会C++。。。
void quicksort(int left,int right){
if(left>right)
return;
int temp=sticks[left],i=left,j=right;
while(i!=j){
while(sticks[j]<=temp&&j>i)
j--;
while(sticks[i]>=temp&&j>i)
i++;
if(i<j){
int t=sticks[i];
sticks[i]=sticks[j];
sticks[j]=t;
}
}
sticks[left]=sticks[i];
sticks[i]=temp;
quicksort(left,i-);
quicksort(i+,right);
}
int dfs(int cur,int k,int cnt){//cur是正在合并的木棍的长度,k是木棍的下标,cnt是合并好的木棍数
if(cnt==num)//完成要求的情况
return ;
if(cur==len)//合并好一根木棍的情况
return dfs(,,cnt+);
int i,pre=;//i是木棍下标,pre保存重复木棍
for(i=k;i<n;i++){
if(book[i]==&&sticks[i]+cur<=len&&sticks[i]!=pre){//
pre=sticks[i];
book[i]=;
if(dfs(sticks[i]+cur,i+,cnt))//
break;
book[i]=;
if(k==)//
return ;
}
}
if(i==n)
return ;
else
return ;
}
int main(){
while(scanf("%d",&n)!=EOF&&n){
int sum=;//总长度
for(int i=;i<n;i++){
scanf("%d",&sticks[i]);
sum+=sticks[i];
}
quicksort(,n-);//注意要从大到小排序,因为合并后木棍的长度一定大于原来最长的
for(len=sticks[];len<=sum/;len++){//剪枝,从最大的长度开始枚举,这里大于sum/2归并为了合成一根木棍的情况
if(sum%len==){//长度是总长因数才符合要求
num=sum/len;
memset(book,,sizeof(book));
if(dfs(,,))
break;
}
}
if(len>sum/)//一根木棍的情况
printf("%d\n",sum);
else
printf("%d\n",len);
}
return ;
}
POJ1011的更多相关文章
- 【poj1011】 Sticks
http://poj.org/problem?id=1011 (题目链接) 题意 给出一大堆小棍子的长度,需要把他们拼成几根长度相等的大棍子,求大棍子的最短长度. Solution 经典搜索题,剪枝剪 ...
- poj1011 Sticks(DFS+剪枝)
题目链接 http://poj.org/problem?id=1011 题意 输入n根棍子的长度,将这n根棍子组合成若干根长度相同的棍子,求组合后的棍子的最小长度.这题是poj2362的加强版,思路与 ...
- poj1011 Sticks[剪枝题]
https://vjudge.net/problem/POJ-1011 此题很重要.★★★ 很欢(e)乐(xin)的一道搜索剪枝题..poj数据还是太水了,我后来想不出来剪枝方法了,就加了句掐了时间语 ...
- poj1011(DFS+剪枝)
题目链接:https://vjudge.net/problem/POJ-1011 题意:给定n(<=64)条木棍的长度(<=50),将这些木棍刚好拼成长度一样的若干条木棍,求拼出的可能的最 ...
- poj1011 Sticks (搜索经典好题)
poj1011 Sticks 题目连接: poj1011 Description George took sticks of the same length and cut them randomly ...
- 北大poj-1011
木棒 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 136132 Accepted: 32036 Description ...
- POJ1011 Sticks
Description George took sticks of the same length and cut them randomly until all parts became at mo ...
- POJ1011 (DFS+剪枝)
Sticks Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 129606 Accepted: 30388 Descrip ...
- Sticks(poj1011/uva307)
题目大意: 乔治有一些碎木棒,是通过将一些相等长度的原始木棒折断得到的,给出碎木棒的总数和各自的长度,求最小的可能的原始木棒的长度:(就是将一些正整数分组,每组加起来和相等,使和尽可能小) 一开始做p ...
随机推荐
- Linux 下解压大全
.tar 解包:tar xvf FileName.tar 或 tar zxvf FilenName.tar打包:tar cvf FileName.tar DirName(注:tar是打包,不是压缩!) ...
- UVA11178 Morley's Theorem(基础模板)
题目链接 题意:给出A,B, C点坐标求D,E,F坐标,其中每个角都被均等分成三份 求出 ABC的角a, 由 BC 逆时针旋转 a/3 得到BD,然后 求出 ACB 的角a2, 然后 由 BC顺时 ...
- 淘淘商城基于maven和svn的理解
首先了解下maven和svn是什么: Maven是一个项目的管理工具,它包含了一个项目对象模型 (Project Object Model),一组标准集合,一个项目的生命周期(Project Life ...
- 使用js进行string和json之间转换的方法
在数据传输过种中,json是以文本,即字符串的形式传递,字符串形似Json对象: var str1 = '{ "name": "Amy", "sex& ...
- easyUI数据表格datagrid之笔记2
/**========================================= * 追加在表格尾部 */function append(){ editIndex = $('#dg').dat ...
- Python学习笔记——基本语法
1.程序输出——print语句 >>> myString = 'Hello World!' >>> print myString Hello World! > ...
- linux 开机启动过程详解
Linux开机执行内核后会启动init进程,该进程根据runlevel(如x)执行/etc/rcx.d/下的程序,其下的程序是符号链接,真正的程序放在/etc/init.d/下.开机启动的程序(服务等 ...
- JS实现表格排序
今天有点闲,写个小东西,使用JS实现点击表格标题栏实现自动排序功能,嘻嘻... 一.JS代码,文件名为code.js如下: (function($){ //插件 $.extend($,{ //命名空间 ...
- codeforces 712C C. Memory and De-Evolution(贪心)
题目链接:http://codeforces.com/problemset/problem/712/C 题目大意: 给连个值x,y (3 ≤ y < x ≤ 100 000), x,y都为等边三 ...
- CMAKE使用
http://www.cppblog.com/tx7do/archive/2010/08/19/124000.html http://blog.csdn.net/dbzhang800/article/ ...