poj_1011_sticks(搜索+剪枝)
2013-05-23 14:05
288 查看
题型:搜索题
题意:此题堪称最经典搜索题。
Description
乔治拿来一组等长的木棒,将它们随机地裁断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。
Input
输入包含多组数据,每组数据包括两行。第一行是一个不超过64的整数,表示砍断之后共有多少节木棍。第二行是截断以后,所得到的各节木棍的长度。在最后一组数据之后,是一个零。
Output
为每组数据,分别输出原始木棒的可能最小长度,每组数据占一行。
Sample Input
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
Sample Output
6
5
分析:
一堆长度不等的木棍儿,如何分组使他们每一组的长度之和相等咧?穷举是肯定的,但是暴力是不可能的。。。
设这一堆木棍的总长度为sum,那么可以想到,想要将其平均分配,每组的总长度肯定是sum的约数,因此只需枚举sum的所有约数就好了;
用DFS解决是靠谱的,但是单纯的来写的话就会光荣的得到一个TLE,因为计算过程中很大一部分是不必要的,因此本题的技巧就在于如何剪枝;
我们要找原来木头可能的最小长度,那么可以用一个每组木棍长度之和的循环,循环的初始值是木棍中最大的长度,循环的边界是所有木棍长度之和,如此便可保证得到可能最小长度的木棍儿。
把木棍儿长度按从大到小进行排序。既可以减少运行时间,又方便剪枝。
好了,关键来了,我们怎么剪枝呢?
1、若要决策的木棍儿正好是需要的全部长度(即为当前拼接的最后一个)后续循环是想要较短的去拼接起来,显然即使拼了起来了,剩这个stick[i]迟早还是要用在某个地方的,所以不可行。
2、如果是重新开始找的,找到一个较短的棍子是不可行的,那么直接放弃这种方案,因为以某个短棍子不行的话,这个短棍子迟早还是要用到,那么,当然还是不可行的。
代码:
题意:此题堪称最经典搜索题。
Description
乔治拿来一组等长的木棒,将它们随机地裁断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。
Input
输入包含多组数据,每组数据包括两行。第一行是一个不超过64的整数,表示砍断之后共有多少节木棍。第二行是截断以后,所得到的各节木棍的长度。在最后一组数据之后,是一个零。
Output
为每组数据,分别输出原始木棒的可能最小长度,每组数据占一行。
Sample Input
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
Sample Output
6
5
分析:
一堆长度不等的木棍儿,如何分组使他们每一组的长度之和相等咧?穷举是肯定的,但是暴力是不可能的。。。
设这一堆木棍的总长度为sum,那么可以想到,想要将其平均分配,每组的总长度肯定是sum的约数,因此只需枚举sum的所有约数就好了;
用DFS解决是靠谱的,但是单纯的来写的话就会光荣的得到一个TLE,因为计算过程中很大一部分是不必要的,因此本题的技巧就在于如何剪枝;
我们要找原来木头可能的最小长度,那么可以用一个每组木棍长度之和的循环,循环的初始值是木棍中最大的长度,循环的边界是所有木棍长度之和,如此便可保证得到可能最小长度的木棍儿。
把木棍儿长度按从大到小进行排序。既可以减少运行时间,又方便剪枝。
好了,关键来了,我们怎么剪枝呢?
1、若要决策的木棍儿正好是需要的全部长度(即为当前拼接的最后一个)后续循环是想要较短的去拼接起来,显然即使拼了起来了,剩这个stick[i]迟早还是要用在某个地方的,所以不可行。
2、如果是重新开始找的,找到一个较短的棍子是不可行的,那么直接放弃这种方案,因为以某个短棍子不行的话,这个短棍子迟早还是要用到,那么,当然还是不可行的。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include <algorithm> using namespace std; bool used[1000]; int a[1000]; int n,sum; int cmp(const void *a,const void *b){ return (*(int *)b-*(int *)a); } bool dfs(int unused,int left,int len,int pos){//unused是木有用过的木棒的个数,left是生下来要拼的的长度,len是目标长度,pos用于记录当前位置 if(left==0&&unused==0){ return true; } if(left==0){ left=len; pos=0; } for(int i=pos;i<n;i++){//剪枝1:记录当前位置,不用再重复遍历; if(used[i]==true){//已用过的就不用了 continue; } if(a[i]>left){//若当前木棍长度大于剩余要拼接的长度,跳过; continue; } used[i]=true;//标记 if(dfs(unused-1,left-a[i],len,i+1)){//深搜 return true; } used[i]=false;//状态恢复 if(len==left||a[i]==left){//剪枝2 break; } } return false; } int main(){ while(scanf("%d",&n)&&n){ memset(used,false,sizeof(used)); sum=0; for(int i=0;i<n;i++){ scanf("%d",&a[i]); sum+=a[i]; } qsort(a,n,sizeof(a[0]),cmp); for(int i=n;i>0;i--){ if(sum%i==0&&sum/i>=a[0]){ if(dfs(n,0,sum/i,0)){ printf("%d\n",sum/i); } } } } return 0; }
相关文章推荐
- 搜索+剪枝——POJ 1011 Sticks
- poj 1011 Sticks(搜索+剪枝)
- poj 1011 hdoj 1455 Sticks(搜索+剪枝)
- poj 1011 hdoj 1455 Sticks(搜索+剪枝)
- poj 1011 Java: sticks
- POJ1011 Sticks
- poj 1011 Sticks
- POJ1011 Sticks
- POJ 1011 Sticks 解题报告
- POJ 1011 Sticks【dfs】
- Poj_1011_Sticks(剪枝)
- POJ 1011 Sticks (经典DFS)
- Poj 1011-Sticks
- poj 1011 sticks
- POJ 1011 Sticks
- POJ - 1011 - Sticks (DFS + 剪枝)
- poj1011——Sticks(dfs+剪枝)
- poj 1011 sticks
- POJ 1011 Sticks
- POJ 1011 Sticks 经典的dfs+剪枝