洛谷 P1120 小木棍(数据加强版)

题目大意:

已知我们有若干一样长的木棍,现在我们任意切,切完后 每段长度小于50,问,假若我们把这些小木棍拼为原来的木棍,那么可以得到的最短长度的原始木棍有多短。

解题思路:

首先,我们明确搜索的木棍范围是[maxl,sigmal/2],其中maxl为所有木棍中最长的长度,sigmal是所有木棍的长度求和。若在指定范围里面搜索不到可拼接方案,我们认为最优长度为sigmal。

我们每次选取多长,选取多少个木棍都是很难确定的,所以我们需要用到dfs搜索,dfs搜索是对搜索空间不明确时候使用的。

这里我们需要用到暴搜,我们搜索的范围是长度, dfs(l , len, idx)

其中l表示我们已经拼了几根,用于给递归一个结束条件。len表示我们已经拼接了多长,用于告诉我们是否可以拼接下一根,以及用于剪枝,idx表明我们从什么长度开始枚举,表明我们需要从这个范围以后开始枚举,让我们不要重复枚举。

在这个问题有三个剪枝可以优化:

首先我们选取木棒时,需要从大到小开始枚举,我们优先选长的木棒。

假若我们是第一根开始枚举,若最长那根都不行,我们就可以退出,因为往后搜索,它的搜索范围更窄。

假若我们是选择的这根加上原始长度等于目标长度,那么我们可以退出搜索。

#include <bits/stdc++.h>
using namespace std;
const int MAXN=70;
int tmt[MAXN];
int target;
int tot;
int maxl,minl;
void dfs(int no,int nolen,int idx){
	if(no==tot/target){
		cout<<target<<endl;
		exit(0);
	}
	if(nolen==target){
		dfs(no+1,0,maxl);
		return ;
	}
	for(int i=idx;i>=minl;i--){
		if(tmt[i]== 0 || nolen+i>target)continue;
		tmt[i]--;
		dfs(no,nolen+i,i);
		tmt[i]++;
		if(nolen==0 || nolen+i==target)break;
	}
}
int main(){
	int n;cin>>n;
	maxl=-1;
	minl=55;
	for(int i=0;i<n;i++){
		int t;cin>>t;
		if(t>50)continue;
		tot+=t;
		tmt[t]++;
		maxl=max(maxl,t);
		minl=min(minl,t);
	}
	for(int len=maxl;len<=tot>>1;len++){
		if(tot%len!=0)continue;
		target=len;
		dfs(0,0,maxl);
	}
	cout<<tot<<endl;
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值