今天搞了一下传说中的经典搜索题——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. Diode -- Pay Attention to Parallel Connection

    The above circuit is right. The two same resistors are integral. Because every diode is different, t ...

  2. sql 编写横竖表转换

    将横表转为竖表,基本思想是: 1)将横表的多条数据,"压"成一条.相当于将这么多条分组,每组"压"成一条数据.利用group by 2) 再对竖表中的列,由特定 ...

  3. 【原】ajaxupload.js上传报错处理方法

    相信大家在工作中经常用到文件上传的操作,因为我是搞前端的,所以这里主要是介绍ajax在前端中的操作.代码我省略的比较多,直接拿js那里的 $.ajaxFileUpload({ url:'www.cod ...

  4. uC/OS-II实现TEST.MAK块

    ################################################################################                     ...

  5. SQL Server编程(02)自定义函数

    在编程过程中,我们通常把特定的功能语句块封装称函数,方便代码的重用.我们可以在SQL Server中自定义函数,根据函数返回值的区别,我们自定义的函数分两种:标量值函数和表值函数. 自定义函数的优点: ...

  6. Unicode 与 UTF 字符标准

    Unicode 国际字符标准(UCS)是一个字符编码系统,它被设计用来支持世界各国不同语言书面文体之间的数据交换.处理以及显示.        Unicode用两个字节表示一个字符.前127个字符与A ...

  7. apache安装错误error: APR not found解决办法

    linux安装时安装种类不同,一些组件包可能不会被安装,导致linux下安装软件的时候缺这个缺那个,今天为大家介绍linux安装apache时报apr找不到的解决办法 方法/步骤   下载依赖包 wg ...

  8. c#正则表达式2

    System.Text.RegularExpressions.Regex ___rx = new System.Text.RegularExpressions.Regex(@""& ...

  9. SQL语句注入

    1:       select *from user where username='admin' and password='123456'  or 1='1';    万能密码 2:       ...

  10. wordpress后台404页面

    就在刚刚,boss需要看公司网站后台,网站是用wordpress搭的,发现全是404,蛋疼,于是google,下面是解决办法: location / { if (-f $request_filenam ...