题目来源:洛谷:https://www.luogu.org/problemnew/show/P1120
WUSTOJ http://acm.wust.edu.cn/problem.php?id=2575&soj=0
★想想就气【其实还是自己太菜】 居然被书坑了,但是自己没有一点主观意识,请教了学长才发现 书上的代码是有问题的 !不能通过所有样例~
★EMMM,实在是不好意思,等我回来再做这题的时候 发现我的代码贴错了~在此说声对不起,该题题解已更新 请放心食用 awa
思路:
采用深搜,但是直接搜肯定是会超时的,必须要巧妙的剪枝~
剪枝一: 短的木棍拼凑更加的灵活,所以我们不妨将木棍按 从长到短排序 方便搜索
剪枝二: 解最小是 最长的木棍的长度 ,而最大是 只剩下一根木棍的时候 即所有木棍的和
剪枝三: 在循环时 只有能被 所有木棍长度和 整除的长度 才可能是答案
剪枝四: 已经找到答案就不用再搜索了
剪枝五: 如果这时last=0 就说明新的搜索刚刚开始 搜谁都行 ,如果刚刚匹配成功 那就是 最好的匹配,不需要再搜索~
剪枝六: 如果下一个f[ i ] 和这一个相等,那不就是重复搜一样的结果嘛,剪枝~
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=100;
const int mod=1e9+7;
typedef long long LL;
bool vis[maxn];
int f[maxn];
int n,m;
bool flag;
inline void read(int &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
int res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
bool cmp(int a,int b) {return a>b;} //从大到小排序
void hhh(int last,int num,int pos,int len)
{
if(num==n&&last==len) {flag=1; return ;}
if(last==len){
last=0;
pos=1;
}
for(int i=pos;i<=n;i++){
if(vis[i]) continue; //选过的直接跳过
if(last+f[i]<=len){
vis[i]=1;
hhh(last+f[i],num+1,i+1,len);
if(flag) return ; //剪枝4
vis[i]=0; //回溯
if(last+f[i]==len||last==0) break; //剪枝5
}
while(f[i]==f[i+1]) i++; //剪枝6
}
}
int main()
{
while(~scanf("%d",&n)&&n){
int sum=0;
for(int i=1;i<=n;i++){
read(f[i]);
if(f[i]>50){ //排除 长度大于50的干扰 洛谷的坑点
n--;
i--;
}
else sum+=f[i];
}
sort(f+1,f+n+1,cmp); //剪枝1
flag=0;
for(int i=f[1];i<=sum;i++){ //剪枝2
if(sum%i==0){ //剪枝3
memset(vis,0,sizeof vis);
m=sum/i;
hhh(0,0,1,i);
if(flag){
cout<<i<<endl;
break;
}
}
}
}
return 0;
}