【经典剪枝】——poj1011——小木棍
Sticks
| Time Limit: 1000MS | Memory Limit: 10000K | |
| Total Submissions: 136541 | Accepted: 32155 |
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 should 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
题意:求 把n个小木棍组成相同长度的大木棍 的最小长度
详解代码:
#include<iostream> #include<string.h> #include<algorithm> using namespace std; int stk[70];//小木棍长度 int vis[70];//标记数组 int n;//nge木棍 int len;//所求长度 bool dfs(int id,int cur,int s)//id——使用的小木棍编号;cur——当前正在拼的小木棍所剩长度;s——所有木棍所剩总长度 { //结束条件:如果当前拼成了一根长为len的木棍,且所有木棍用完了 if(cur==0) { s-=len; if(s==0) return true; /*************剪枝(4)************/ //开始拼下一根木棒,继续从没用过的最大的开始拼 for(id=0;vis[id]==1;id++); vis[id]=1; //由于排序过,找到的第一根肯定最长,也肯定要使用,所以从下一根开始搜索 if(dfs(id+1,len-stk[id],s)) return true; vis[id]=0; s+=len; } else//一根木棍尚未拼完 { for(int i=id;i<n;i++) { /*************剪枝(5)************/ //相同长度的木棍引出完全相同的解答树,故可以去掉 if(i>0&&stk[i]==stk[i-1]&&vis[i-1]==0)continue; /*************剪枝(6)************/ //可行性:下一根木棍加上之后不能更大于len if(stk[i]<=cur&&vis[i]==0) { cur-=stk[i]; vis[i]=1; if(dfs(i,cur,s)==true)return true; cur+=stk[i]; vis[i]=0; /*************剪枝(1)************/ //一根拼完,直接跳出(威力强大,易忽略的一点) if(stk[i]==cur) break; } } } return false; } bool cmp(int a,int b) { return a>b; } int main() { int flag; while(cin>>n,n) { flag=0;//标记除了sum之外是否找到解 int sum=0; memset(vis,0,sizeof(vis)); for(int i=0;i<n;i++) { cin>>stk[i]; sum+=stk[i]; } /*************剪枝(1)************/ //排序——先找较大的木棍,以减小搜索次数 sort(stk,stk+n,cmp); /*************剪枝(2)************/ //组合木棍一定比原最长木棍长 for(len=stk[0];len<=sum/2;len++) { /*************剪枝(3)************/ //要把sum长度分成为len的n堆,那么,sum一定是len的倍数 if(sum%len==0) { if(dfs(0,len,sum)==true) { cout<<len<<endl; flag=1; break; } } } //只拼一根木棍 if(flag==0) { cout<<sum<<endl; } } return 0; }

浙公网安备 33010602011771号