【搜索剪枝】

搜索剪枝

用于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;
}
posted @ 2024-12-07 14:53  White_ink  阅读(5)  评论(0)    收藏  举报