小木棍 [数据加强版]

洛咕

双倍经验---多组数据

题意:乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50.现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度.给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度.

分析:首先读入的时候把长度大于50的自动过滤掉,剩下n根长度小于等于50的木棍,设这n根小木棍的长度和为(tot),长度最大的为(val).

我们直接从小到大枚举原始木棍的长度,并通过dfs判断是否合法即可.枚举的下界是一个小木棍的最大长度(val),上界是长度和(tot).设当前枚举的原始木棍的长度为(len),那么(tot)必然要能被(len)整除,否则不合法,若能够被整除,显然我们要是能够拼凑出(sum=tot/len)根长度为(len)的木棍就是合法答案.

接下来就只要考虑dfs的剪枝操作了.

一,我们把木棍长度从大到小排序,优先考虑较长的木棍,显然能减少状态数.

二,既然剪枝一已经把木棍排序了,那么我们干脆固定每次填入的木棍长度是递减的.这个只要dfs的变量增加一个last,表示当前从第last根木棍开始考虑就好了.

三,假设我们给一根"空"的 填入木棍,也就是当前的木棍长度(cnt=0),那么当填入(a[i])后该搜索状态不合法,那么直接判定当前分支不合法,因为你把(a[i])填入剩下的其它的"空"的,都会是不合法的.

四,跟三类似,如果我们当前填完了(a[i])之后,填完了一个长度为len的木棍,发现该搜索状态不合法,那么直接判定当前分支不合法,因为你再用别的若干根短的木棍来代替(a[i]),那么接下来搜索下一根木棍还会是不合法的.

五,如果填入(a[i])不合法,如果(a[i+1]=a[i])那么直接不要考虑填.

这些剪枝真的是缺一不可.亲测~~~

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=105;
int n,tot,val,sum,len;
int a[N],visit[N];
//当前正在拼第now跟木棒
//第now跟木棒已经拼出了长度cnt
//当前已经考虑到了第last根木棍
inline bool dfs(int now,int cnt,int last){
	if(now>sum)return true;//sum根木棒都拼完了
	if(cnt==len)return dfs(now+1,0,1);//当前这根拼完了
	int fail=0;//剪枝五用的
	for(int i=last;i<=n;++i){
		if(!visit[i]&&cnt+a[i]<=len&&fail!=a[i]){
			visit[i]=1;
			if(dfs(now,cnt+a[i],i+1))return true;
			fail=a[i];//记录不要填与a[i]相同长度的木棍了
			visit[i]=0;//回溯
			if(!cnt||cnt+a[i]==len)return false;//剪枝三,四
		}
	}
	return false;
}
int main(){
	int nn=read();
	for(int i=1;i<=nn;++i){
		int b=read();
		if(b<=50){//过滤不合法的木棍
			a[++n]=b;tot+=b;//记录长度和
			val=max(b,val);//比较最长木棍
		}
	}
	sort(a+1,a+n+1);reverse(a+1,a+n+1);//从大到小排序
	for(len=val;len<=tot;++len){//枚举原始木棍长度为len
		if(tot%len)continue;//不能整除肯定不合法
		sum=tot/len;//要拼凑出sum根木棍
		memset(visit,0,sizeof(visit));//初始化
		if(dfs(1,0,1)){
			printf("%d
",len);
			break;
		}
	}
    return 0;
}

原文地址:https://www.cnblogs.com/PPXppx/p/11385261.html