AcW木棒-XMUOJ恢复破碎的符咒木牌-DFS与剪枝

题目

思路

话不多说,直接上代码

代码

/*
AcW木棒-XMUOJ恢复破碎的符咒木牌 
搜索顺序:从小到大枚举最终的长度 len
		  从前往后依次拼每根长度为len的木棍 
优化:
1.优化搜索顺序:优先选择深度短的来搜索,故从大到小去枚举
2.排除冗余的方案:每一根长木棍的内部的编号递增(排列方案变为组合方案)、
3.可行性剪枝:
	(1)当前第i根木棍失败,跳过与当前木棍长度相等的其他木棍 
	(2)拼了几根长木棍后,要拼新的木棍,第一个未被用过的木棍,
		如果作为新长木棍的第一段,无解,则直接回溯
	(3)拼了几根长木棍后,要拼最后一段的木棍,
		当前小木棍加入使得当前长木棍满足,但是剩余的木棒拼不出长木棒,无解,回溯 
*/
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=70;
int w[N];//当前木棍的长度 
bool st[N];//是否用过
int sum,len; //当前木棍的总长度,枚举的长度 
int n;
//u:当前正在构造第几根长木棍
//cur:当前正在拼的长木棍的长度
//start: 当前长木棍中小木棍的下标 
bool dfs(int u,int cur,int start){
	if(u*len==sum)return true;//排完所有的小木棍了 
	if(cur==len)return dfs(u+1,0,0);//当前长木棍已经排好 
	for(int i=start;i<n;i++){
		if(st[i] )continue;//如果已经用过 
		if(cur+w[i]<=len){
			st[i]=true;
			if(dfs(u,cur+w[i],i+1)) return true;
			st[i]=false;//恢复现场 
		}
		if(!cur||cur+w[i]==len) return false;//到达这一步说明前面已经无解 
		int j=i;
		while(j<n&&w[i]==w[j])j++;//把与i相等的跳过
		i=j-1;//恢复下标 
	} 
	
	return false;
}


int main(){
	while(cin>>n,n){
		sum=len=0;
		for(int i=0;i<n;i++){
			cin>>w[i];
			sum+=w[i];
			len=max(len,w[i]);
		} 
		sort(w,w+n,greater<int>()); 
		memset(st,0,sizeof st);
		while(true){
			if(sum%len==0&&dfs(0,0,0)){
				cout<<len<<endl;
				break;
			}
			len++;
		}
	}

	return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值