题目来源:洛谷:https://www.luogu.org/problemnew/show/P1120
WUSTOJ http://acm.wust.edu.cn/problem.php?id=2575&soj=0
★想想就气【其实还是自己太菜】 居然被书坑了,但是自己没有一点主观意识,请教了学长才发现 书上的代码是有问题的 !
思路:
采用深搜,但是直接搜肯定是会超时的,必须要巧妙的剪枝~
剪枝1:初始长度的范围一定在 a[1] - sum 之间
剪枝2:所有木棍的和为sum,那么初始长度len 必定可以整除sum
剪枝3:短的木棍拼凑越灵活,从大到小排序可以优化
剪枝4:相同长度的木棍不需要搜索多次
剪枝5:等于是最佳匹配 不必再搜索
还有一些地方有剪枝 不一一说明了~
另外其实二分也可以做,只是数据不大,懒得用233
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
int a[maxn];
bool vis[maxn],flag;
int n,m,l;
void hhh(int k,int last,int len)
{
if(k==m) {flag=1; return;}
if(len==0){
for(int i=1;i<=n;i++)
if(!vis[i]){
vis[i]=1;
hhh(k+1,i,l-a[i]);
vis[i]=0;
return ;
}
}
for(int i=last+1;i<=n;i++){
if(!vis[i]&&len>=a[i]){
vis[i]=1;
hhh(k,i,len-a[i]);
vis[i]=0;
if(a[i]==len) break; // 剪枝5
int j=i;
while(i<n&&a[i]==a[j]) i++; //剪枝4
}
}
}
bool cmp(const int &a,const int &b) {return a>b;}
int main()
{
while(cin>>n){
int sum=0;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]>50) {
i--;
n--;
}
else{
sum+=a[i];
}
}
sort(a+1,a+n+1,cmp); //剪枝3
for(int i=a[1];i<=sum;i++){ //剪枝1
if(sum%i==0){ //剪枝2
memset(vis,0,sizeof vis);
vis[1]=1;
flag=0;
m=sum/i;
l=i;
hhh(1,1,l-a[1]);
if(flag){
cout<<l<<endl;
break;
}
}
}
}
return 0;
}