木棒
给出n件物品,第i件物品的质量为\(c_i\),询问分成的一些,保证每组物品的质量之和相等,使每组物品质量之和尽可能下,其中\(n\leq 64,c_i\leq 50\)。
解
数据范围很小,可以考虑搜索,以下给出优化过程。
-
显然当每组质量\(s\)相等,设所有物品的总质量为\(sum\),那么s必然为\(sum\)的约数,于是我们只要从小到大枚举s为sum的约数即可,而且记最大的物品质量为\(mx\),那么s必然大于等于\(mx\)。
-
搜索框架为每一组放哪些物品,不选择每件物品放哪些组的原因在于,不好判断质量之和是否相等。
-
显然可以最优性剪枝,当当前搜索状态对应的答案大于等于已经搜出的答案,可以return
-
显然可以改变搜索顺序,先搜索质量大的物品。
-
显然可以进行去重,首先每一组的物品放入顺序编号递增
-
显然可以去重,对于质量相同的物品,当其中一件失败了,其他没必要尝试
-
当放入一组的第一件物品,如果他失败了,后面的必然失败,return掉.
-
当放入一组的最后一件物品,如果他失败了,后面放入的物品情况被前者包含,因此没必要尝试,return掉。
参考代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define il inline
#define ri register
using namespace std;
bool v[100];
int n,len[100],sum,
mx,gt,gn;
il void read(int&);
bool dfs(int,int,int);
int main(){
while(read(n),n){sum=mx=gt=0;
for(int i(1);i<=n;++i){read(gn);
if(gn<=50)sum+=gn,mx=max(gn,mx),
len[++gt]=gn;
}n=gt,memset(v,0,sizeof(v));
sort(len+1,len+n+1,greater<int>());
for(int i(mx);i<=sum;++i){
if(sum%i)continue;gt=i,gn=sum/i;
if(dfs(1,0,0)){
printf("%d\n",i);break;
}
}
}
return 0;
}
bool dfs(int a,int last,int cnt){
if(a>gn)return true;
if(cnt==gt)return dfs(a+1,0,0);
int fail(0);
for(int i(last+1);i<=n;++i){
if(v[i]||len[i]+cnt>gt||fail==len[i])continue;
v[i]|=true;if(dfs(a,i,cnt+len[i]))return true;
v[i]&=false,fail=len[i];if(cnt+len[i]==gt||!cnt)
return false;
}return false;
}
il void read(int &x){
x^=x;ri char c;while(c=getchar(),c<'0'||c>'9');
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}