传送门:
POJ:http://poj.org/problem?id=1011
HDOJ:http://acm.hdu.edu.cn/showproblem.php?pid=1455
HOJ:http://acm.hit.edu.cn/hoj/problem/view?id=1049
Sticks
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 5206 Accepted Submission(s): 1456
Problem Description
George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.
Input
The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.
Output
The output file contains the smallest possible length of original sticks, one per line.
Sample Input
9 5 2 1 5 2 1 5 2 1 4 1 2 3 4 0
Sample Output
6 5
解题报告:
这是一道经典的搜索剪枝题。
解法:
在刚开始搜索组成一支新的长为 L 的木棍时,我们总是以当前最长的,未被使用的,木棍开始,如果搜索不成功,那么以比它短的开始, 这时也一定不能取得全局的成功。因为每一支题目给出的木棍都要被用到。代码如下:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
bool visited[65];//标记是否访问过
int snum; //分火柴棍
int sum;//总分火柴棍长度之和
int sticks[65];//储存分火柴棍
int l;//合起来每根火柴棍长度
int num;//合起来有多少根火柴棍
bool dfs(int s,int slen,int pos){//s当前已经分配好的火柴棍,slen当前总长度,pos当前第几个火柴棍
if(s==num)
return true;
bool sign =(slen==0?true:false);
for(int i=pos+1;i<snum;i++){
if(visited[i]==true) //该根火柴访问过
continue;
if(slen+sticks[i]==l){
visited[i]=true;
if(dfs(s+1,0,-1))
return true;
else{
visited[i]=false;
return false;
}
}
else if(slen+sticks[i]<l){
visited[i]=true;
if(dfs(s,slen+sticks[i],i)) //没达到继续加下一根
return true;
else{
visited[i]=false;
if(sign)
return false;
}
}
}
return false;
}
bool cmp(int a,int b){
return a>b;
}
int main(){
while(scanf("%d",&snum)==1&&snum){
sum=0;
for(int i=0;i<snum;i++){
scanf("%d",&sticks[i]);
sum+=sticks[i];
}
sort(sticks,sticks+snum,cmp);
for(l=sticks[0];l<=sum;l++){
if(sum%l==0){
num=sum/l;
memset(visited,false,sizeof(visited));
if(dfs(1,0,-1)){//第一次找到的肯定是最大的
printf("%d\n",l);
break;
}
}
else
continue;
}
}
return 0;
}