今天搞了一下传说中的经典搜索题——poj1011,果然里面充斥着各种巧妙的剪枝,做完之后回味一下还是感觉构思太巧妙,所以总结记录一下加深理解。

原题:http://poj.org/problem?id=1011

刚开始接触搜索的初学者面对这道题可能感觉无从下手,即便是告诉了要用深搜解决这道题,也不知道怎么用,我现在也对搜索有了更多的理解与体会,其实不要把搜索只理解为在一个地图上找点,其实搜索更可以抽象为当面对多个选择的时候如何抉择,深搜就是先认准一个方向走下去,不行再回来,走别的路;广搜就是把每一次能做的选择都试一遍。所以,这道拼木棍的题就是一道很好的深搜题。我们不知道哪根木棍可组合进来,那不如就按从前往后的顺序一个一个试。

唠叨了半天,终于该放代码了。。简单的注释我写在程序里了,稍微长一点的解释,我程序里有序号,我把详细的解释写在外面,大家对一下序号来看。

PS:我不能确定我写的已经是优化到最好了,也希望有更好想法的小伙伴可以在评论里教下我,谢谢~如果喜欢别忘了点赞哟~

  1. 这里要解释的是sticks[i]!=pre,假设有几根木棍是5 5 5 2,这时,若确定第一根已经不满足条件了,后面两根长度为5的木棍也没有必要去试了,所以跳过就好了。这里可能会有小伙伴理解为这样会导致不能正确的加入两根相同的木棍(我最初就这样想的。。),比如5 2 5 1 1,会理解为最后一个1加不上了。其实当第一个1符合条件的情况下,函数会再次调用,所以新调用的函数了pre又是0了,所以这个条件完美排除了第一根就不符合条件的情况,并没有影响重复长度木棍第一根符合要求的情况。
  2. 这里dfs的返回值若为1,说明已经完成题目要求了(前面只有cnt==num才返回1),所以可以跳出循环,这会影响后面if语句的判断,若是跳出的,说明找到了,若不是跳出,正常结束循环,说明没有找到。
  3. 这个剪枝也很巧妙,它是考虑了,当我每合并一个新木棍时,第一根木棍是很特殊的,我们每次从前往后挑选木棍时,总是选没用过且长度符合要求的,这也就意味着,当我们选中了第一根木棍时,它的长度是符合要求的,这一根是一定要用的(无论对于哪个合成的木棍,这根都会是作为第一根用,这里大家好好琢磨一下),所以若前面的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的更多相关文章

  1. 【poj1011】 Sticks

    http://poj.org/problem?id=1011 (题目链接) 题意 给出一大堆小棍子的长度,需要把他们拼成几根长度相等的大棍子,求大棍子的最短长度. Solution 经典搜索题,剪枝剪 ...

  2. poj1011 Sticks(DFS+剪枝)

    题目链接 http://poj.org/problem?id=1011 题意 输入n根棍子的长度,将这n根棍子组合成若干根长度相同的棍子,求组合后的棍子的最小长度.这题是poj2362的加强版,思路与 ...

  3. poj1011 Sticks[剪枝题]

    https://vjudge.net/problem/POJ-1011 此题很重要.★★★ 很欢(e)乐(xin)的一道搜索剪枝题..poj数据还是太水了,我后来想不出来剪枝方法了,就加了句掐了时间语 ...

  4. poj1011(DFS+剪枝)

    题目链接:https://vjudge.net/problem/POJ-1011 题意:给定n(<=64)条木棍的长度(<=50),将这些木棍刚好拼成长度一样的若干条木棍,求拼出的可能的最 ...

  5. poj1011 Sticks (搜索经典好题)

    poj1011 Sticks 题目连接: poj1011 Description George took sticks of the same length and cut them randomly ...

  6. 北大poj-1011

    木棒 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 136132   Accepted: 32036 Description ...

  7. POJ1011 Sticks

    Description George took sticks of the same length and cut them randomly until all parts became at mo ...

  8. POJ1011 (DFS+剪枝)

    Sticks Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 129606   Accepted: 30388 Descrip ...

  9. Sticks(poj1011/uva307)

    题目大意: 乔治有一些碎木棒,是通过将一些相等长度的原始木棒折断得到的,给出碎木棒的总数和各自的长度,求最小的可能的原始木棒的长度:(就是将一些正整数分组,每组加起来和相等,使和尽可能小) 一开始做p ...

随机推荐

  1. Linux下shell脚本中信号捕获和函数练习脚本之ping一个网段

    该脚本主要的目的是练习在Linux bash脚本中捕获信号,顺便练习一下函数的使用,还有就是终止一个正在运行的程序后,该程序打开的文件的后续处理问题等等!脚本功能:  ping一个网段内的IP,检测哪 ...

  2. 理解和使用 JavaScript 中的回调函数

    理解和使用 JavaScript 中的回调函数 标签: 回调函数指针js 2014-11-25 01:20 11506人阅读 评论(4) 收藏 举报  分类: JavaScript(4)    目录( ...

  3. Docker入门教程(三)Dockerfile

    Docker入门教程(三)Dockerfile [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第三篇,介绍了Dockerfile的语法,DockerOn ...

  4. linux安装ftp组件

    1   安装vsftpd组件 linux系统安装完后,有/etc/vsftpd/vsftpd.conf 文件,是vsftp的配置文件. [root@bogon ~]# yum -y install v ...

  5. O(1)快速乘注意事项

    O(1)快速乘是经典玄学优化啦~由于刚挂了一次特此总结一番. ll mul(ll u,ll v){ return(u*v-ll((long double)u*v/p)*p+p)%p; } double ...

  6. js009-客户端检测

    js009-客户端检测 本章内容: 1.使用能力检测 2.用户代理检测的历史 3.选择检测方式 一般不使用客户端检测. 9.1 能力检测 也称特性检测.基本模式如下: if(object.proper ...

  7. 史上最全的Linux常用命令

    系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS ...

  8. oracle表字段为汉字,依据拼音排序

    在order by后面使用NLSSORT函数转化汉字列,如下 select * from student order by NLSSORT(name,'NLS_SORT=SCHINESE_PINYIN ...

  9. 使用System Sound Services 播放音效(最简单,比较底层),调用AudioServicesPlaySystemSound()

    1.适用范围:一些很小的提示或警告音频. 2.使用限制: 声音长度不能超过30秒 声音文件必须是PCM或IMA4(IMA/ADPCM)格式.(有时候可播放一些特殊的.mp3) 打包成.caf..aif ...

  10. JavaScript数据操作--原始值和引用值的操作本质

    我的一句话总结:原始值不管是变量赋值还是函数传递都不会改变原值,引用值不管是变量赋值还是函数传递,如果新变量重新赋值,则不会影响原引用值,如新变量是直接操作,就会影响原引用值. 首先明确,值和类型是两 ...