这道题 是 比较经典的 搜索题。
题意:
给出一堆小木棍的长度,需要把它们拼成几根相同的大棍子,求 这些大棍子的最短长度
分析:这道题主要使用,深度搜索+递归,当然这里用到多次剪枝,这对于减小时间复杂度很有效。
#include<iostream>
#include<algorithm>
using namespace std;
int stick[64];
int used[64];
int len;
int n;
bool DFS(int i,int l,int s){ //i表示棍子序号,l表示拼成一根棍子还需多长,s表示所有棍子的总长度
if(l == 0){
s = s - len;
if(s == 0)
return true;
for(i=0;used[i];i++); //剪枝,从没有用过的树枝开始
used[i] = 1;
if(DFS(i+1,len-stick[i],s)) return true;
used[i] = 0;
s = s + len;
}
else{
for(int j=i;j<n;j++){
if(j>0&&(stick[j]==stick[j-1]&&!used[j-1])) //剪枝,长度一样的木棍,前面如果没用到,相应的,后面的也是没用的
continue;
if(!used[j]&&l>=stick[j]){ //剪枝,需要的长度肯定要大于等于当前的木棍长度
l = l - stick[j];
used[j] = 1;
if(DFS(j,l,s)) return true;
used[j] = 0;
l = l + stick[j];
if(stick[j] == l) //执行到这步,说明当前的木棍可以,但是后面的搜索失败,所以得退回上一级
break;
}
}
}
return false;
}
bool cmp(const int a,const int b){
return a>b;
}
int main(){
int i,sum;
while(cin>>n,n){
sum = 0;
for(i=0;i<n;i++){
cin>>stick[i];
sum = sum + stick[i];
used[i] = 0;
}
sort(stick,stick+n,cmp);
bool flag = false;
for(len = stick[0];len<=sum/2;len++){ //剪枝,原始长度 肯定大于 剪过之后最长的,小于总和
if(sum % len == 0){ //剪枝,总和肯定能被 原始长度len整除
if(DFS(0,len,sum)){
flag = true;
cout<<len<<endl;
break;
}
}
}
if(!flag)
cout<<sum<<endl;
}
return 0;
}
至于为什么要将 树枝 从大到小 排列,从一篇 博客里 有写,这样能使 后面的 选择更加灵活些。
关于剪枝,实质上,我觉得就是 除去一些 不需要考虑的无关情况,加快程序的执行。