【搜索剪枝】
搜索剪枝
用于DFS
常见剪枝方法
1.优化搜索顺序
2.排除等效冗余
3.可行性剪枝:上下界剪枝
4.最优性剪枝:当前已经超过了最优解
5.记忆化搜索:重复遍历一个状态时直接检索并返回
【例题】
木棒
https://www.acwing.com/problem/content/description/169/
首先明确概念
木棍:被拼的
木棒:被木棍裁断
思路
【搜索】
枚举木棍长度,查看每个长度下是否有可行解
【剪枝】
(1)可行性剪枝:sum%length一定要是0(一定要整除)
(2)优化搜索顺序:从大到小枚举(先排序)
(3)排除等效冗余:
① 按照组合数方式枚举
② 如果当前木棍加到当前棒中失败了,则直接略过后面所有长度相等的木棍
③ 如果木棒的第一根木棍失败了,则整个方案一定失败(因为没有一个木棒可容纳这根木棍)
④ 若最后一根失败->同③
#include<bits/stdc++.h>
using namespace std;
const int N=100;
int n,a[N];
bool st[N];//判断该木棒有没有被用过
int length=0,sum=0,val=0;
//u:木棍个数
//s:当前拼的木棍长度
//last:上一根被拼的木棒编号
bool dfs(int u,int s,int last){
if(u*length==sum) return true;//长度已到 满足条件
if(s==length) return dfs(u+1,0,0);//一根已拼完 dfs下一根
for(int i=last;i<n;i++){//从大到小搜:上一次的最大到最小
//可行性剪枝:没用过且长度要小
if(st[i] || s+a[i]>length) continue;
st[i]=true;
//dfs下一层
if(dfs(u,s+a[i],i+1)) return true;
//回溯过程剪枝
st[i]=false;
//头尾都失败了:整个方案失败
if(!s || s+a[i]==length) return false;
int j=i;//把相同长度的木棒都筛掉
while(j<n && a[j]==a[i]) j++;
i=j-1;
}
return false;
}
int main(){
while(cin>>n,n){
length=0;
sum=0;
val=0;
memset(st,0,sizeof st);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
val=max(val,a[i]);
sum+=a[i];
}
sort(a,a+n);
reverse(a,a+n);
for(length=val;length<=sum;length++){
//必须整除
if(!(sum%length)){
if(dfs(0,0,0)){
printf("%d\n",length);
break;
}
}
}
}
return 0;
}