poj 1011 深搜
题意:长度相同的原始木棍被砍断,现在想将小木棍拼接成原始木棍,求原始木棍的最小可能长度。
分析:经典剪枝
1.越长的木棍对后面木棍的约束力越大,因此要把小木棍排序,按木棍长度从大到小搜索,这样就能在尽可能靠近根的地方剪枝。
2.当前木棍能恰好填满一根原始木棍,但剩余的木棍无法组合出合法解,如果用更短的木棍组合来代替这根木棍,当前木棍不可能和剩下的其它木棍组合出合法解。
3.考虑每根原始木棍的第一根木棍,如果无法得出合法解,就不必考虑下一根木棍了,因为当前木棍一定是作为某根原始木棍的第一根木棍。
4.跳过重复长度的木棍。
5.最后一根木棍不必搜索,因为原始木棍长度是总木棍长度的约数。
int a[1000],b[1000]; int n; //总数 int len; //原始长度 int totallen;//总长度 int nowlen; //当前长度 int start; //开始位置 int flag; //标记 bool cmp(int a,int b){ return a>b; } void DFS(){ int i,tstart=start; for(i=tstart;i<n;i++) { if(flag) return; if(b[i]==0 && nowlen+a[i]<=len) { b[i]=1; nowlen+=a[i]; if(nowlen==len) { nowlen=0; totallen-=len; start=1; if(totallen==len){flag=1;return;} DFS(); nowlen=len; totallen+=len; start=tstart; } else if(nowlen<len){start=i+1; DFS(); start=tstart;} b[i]=0; nowlen-=a[i]; if(nowlen+a[i]==len||nowlen==0) break; while(i<n-1&&a[i]==a[i+1]) i++; } } } int main() { while(cin>>n&&n!=0) { int i; totallen=nowlen=flag=0; for(i=0;i<n;i++) { cin>>a[i]; totallen+=a[i]; b[i]=0; } sort(a,a+n,cmp); int total=totallen; for(i=a[0];i<total;i++) if(total%i==0) { len=i; DFS(); if(flag) { cout<<i<<endl; break; } } if(i==total) cout<<total<<endl; } return 0; }