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 ...
随机推荐
- NOIp 0910 爆零记
这套题是神犇chty出的. 刚拿到题的时候有点懵逼,因为按照一般的套路第一题都是一眼题,但是看到第一题后想了很多个算法和数据结构好像都不能很好的解决.然后就随手敲了个暴力去看T2. 嗯...文件名是b ...
- JavaScript函数之美~
JavaScript函数之美~ 这篇文章,我将就以下几个方面来认识JavaScript中的函数. 函数为什么是对象,如何定义函数? 如何理解函数可以作为值被传递 函数的内部对象.方法以及属性 第一部分 ...
- Docker入门教程(七)Docker API
Docker入门教程(七)Docker API [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第七篇,重点介绍了Docker Registry API和 ...
- python 模拟登陆,请求包含cookie信息
需求: 1.通过GET方法,访问URL地址一,传入cookie参数 2.根据地址一返回的uuid,通过POST方法,传入cooki参数 实现思路: 1.理解http的GET和POST差别 (网上有很多 ...
- cocos2d 2.2.6 win7下的配置
我搭建cocos2.6的开发环境需要安装工具包括: 1.Visual Studio 2012(由于不兼容win7,需要安装Update 4)和虚拟光驱daemon tool,虚拟光驱的下载地址:htt ...
- C#中int,string,char[],char的转换(待续)
//char[]转string string mm = "woshicainiao"; char[] ss = mm.ToCharArray(); string AA = new ...
- 英文分词算法(Porter stemmer)
http://blog.csdn.net/whuslei/article/details/7398443 最近需要对英文进行分词处理,希望能够实现还原英文单词原型,比如 boys 变为 boy 等. ...
- Foundation框架--字典( NSDictionary NSMutableDictionary )
基础知识 1.字典不允许相同的key,但允许有相同的value. 2,字典是无序的,字典不能排序. 3.字典里的内容是成对存在的,不会出现单数. 4.快速创建的方式只适合不可变字典. 不可变字典 #i ...
- CentOS7 Mini安装Oracle(图形化安装)
以下操作在root用户下进行 1.mini版centos7没有ifconfig指令,可以如下操作 [root@localhost ~]# yum upgrade [root@localhost ~]# ...
- Java数据结构——栈
//================================================= // File Name : Stack_demo //-------------------- ...