十分经典的一道dfs剪枝问题
原题链接:
167. 木棒 - AcWing题库https://www.acwing.com/problem/content/description/169/
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 64;
int n,sum,length;
int sticks[N];
bool st[N];
bool dfs(int u,int cur,int start)//u拼成的大木棒数量
{//start:待拼的小木棒的下标
if(u*length==sum)//如果大木棒的数量*长度==木棒长度总和,说明找到一种答案,返回真
return true;
if(cur==length) return dfs(u+1,0,0);
for(int i = start;i < n;i ++){
if(st[i]) continue;
int l = sticks[i];
if(cur+l>length) continue;//这里跳过的话,不就相当于下标为i的小木棒再也用不到了吗?不明白!
//解释上面的问题,这里跳过的话,只是这个小木棒不能填这个大木棒,填下一个木棒的时候,还可以继续用
st[i] = true;
if(dfs(u,cur+l,i+1)) return true;//这是为什么
st[i] = false;
if(!cur) return false;//该小木棒在开头拼失败了
if(cur+l ==length) return false;//该小木棒在结尾拼失败了
int j = i;//跳过相同的
while(j<n && sticks[j]==l) j++;
i = j-1;
}
return false;
}
int main()
{
while(cin>>n,n){
sum =0,length =0;
for(int i =0;i<n;i++){
int l;//每根小木棒的长度
cin>>l;
if(l>50)continue;
sticks[i] = l;//储存在数组中
sum += l;//小木棒长度之和
length = max(length,l);//最长的小木棒,从该长度开始枚举,因为最短大木棒也肯定比最长的小木棒长,也算是一种剪枝
}
sort(sticks,sticks+n);reverse(sticks,sticks+n);//从长木棒开始枚举,也是剪枝
memset(st,false,sizeof st);//初始化,所有木棒都可以枚举
// for(int i = 0;i<n;i++){
// if(sticks[i]>50)
// st[i] = true;
// }
while(length){
if(sum % length ==0 && dfs(0,0,0)){
cout<<length<<endl;
break;
}
length++;
}
}
return 0;
}