小木棍-搜索剪枝

小木棍,多么经典的题目啊,几年都拿出来做一下,今年终于感觉有点明白了(真为中年妇女的智商着急啊:()

题解抄的luogu题解,修改了以前抄的代码,终于ac了.

主要难点在于如何进行dfs的剪枝可以二分答案(不二分也不会超时,我的代码没有二分),dfs看看这个答案可不可行虽然数据很小,直接dfs也是会超时的,所以需要加入一些剪枝。

1.从max(最大木棍长度,总木棍长度/要分的段数)为左面,所有木棍长度为右面二分答案。
2.木棍长度要排序,方便每次dfs从小到大,为避免重复搜索(比如说2 3 4 和2 4 3)定义一个pos,每次枚举从pos开始,这也是为什么排序的原因之一。//我原来没有这个剪枝,得66分.
3.如果现在搜索状态的剩余长度和二分答案的长度相等,还搜不出答案,说明有木棍无解,直接break跳出循环。//这条没用,没写二份答案
4.如果现在搜索状态的剩余长度和循环搜索到木棍的长度相等,那么下一次dfs的状态如3,还搜不出答案,说明有木棍无解,直接break跳出循环。
5.如果这个长度的木棍搜不出答案,相同长度的也搜不出答案。

#include
#include
#include
#include
using namespace std;
int a[110];//存小棒长大小最好大于64
int visited[110];//标记小棒是否被用
int n;//小棒个数
bool cmp( int a,int b) {
	return a>b;
}

int DFS(int len,int pos,int remains_len,int num) {
	if(remains_len==0&&num==0)//都拼完了
		return len;
	if(remains_len==0) { //又拼接起一根
		remains_len=len;
		pos=0;
	}
	for(int i=pos; i=a[i]) {
			visited[i]=1;
			if(DFS(len,i+1,remains_len-a[i],num-1)) return len;
			visited[i]=0;
			if(a[i]==remains_len||len==remains_len) //a[i]已经太长,后面的更长,剪枝
				break;
			while(a[i]==a[i+1])//已经试过的长度,不用再重复试。
				i++;
		}
	}
	return 0;
}
int main() {
	while(cin>>n&&n) {
		int sum=0;//所有小棒长度
		int len,k;
		for(int i=0; i>a[i];
			if(a[i]>50) {
				i--;
				n--;
			} else
				sum+=a[i];
		}
		sort(a,a+n,cmp);
		for(len=a[0]; len<=sum; len++) {
			memset(visited,0,sizeof(visited));
			if(sum%len==0) {
				k=DFS(len,0,0,n);
				if(k)  break;
			}
		}
		cout<


你可能感兴趣的:(搜索)