题解 P1120 【小木棍 [数据加强版]】
George1123 · · 题解
P1120 【小木棍 [数据加强版]】传送门
此题算法:暴搜
由于错误思想太多了,题解只讲正确算法
1.输入木棍长度,算出合法木棍的数量
t ,长度和sum ,长度最大值maxn ,并将木棍桶排序。2.枚举长木棍长度
len ,tot 表示拼成的长木棍数量。然后dfs ,四个参数中k 表示拼到第几根长木棍,rest 表示当前拼的长木棍剩余需拼长度,lon 表示拼一个新长木棍时枚举最长的小木棍长度,st 表示在拼某一个长木棍时依次枚举的小木棍长度。3.如文中剪枝,
dfs 的返回值是方案是否可行,第一个可行的方案中,len 就是答案。
以下是代码
#include <bits/stdc++.h>
using namespace std;
int n,in[70],maxn;
int t,a[70],sum,ans;
int num[70],len,tot;
inline int read(){
int f=1,dig=0;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
} while(ch>='0'&&ch<='9'){
dig=(dig<<3)+(dig<<1)+ch-'0';
ch=getchar();
} return f*dig;
}
//lon表示:每次要拼一个新的长木棍时,
//枚举的最长的小木棍的长度
//(显然,这个值是非递增的,每次向下枚举)
//st表示:在拼某一个长木棍时,依次枚举的小木棍长度。
//(这个也是非递增的,每次可以从start向下枚举)。
bool dfs(int k,int rest,int lon,int st){
if(k==tot+1) return 1;
if(!rest) return dfs
(k+1,len,lon,lon);
st=min(st,rest);
for(int now=st;now;now--)
if(num[now]){
num[now]--;
int tmp;
if(len==rest)
tmp=now;
else tmp=lon;
if(dfs(k,rest-now,tmp,now))
return 1;
//如果Len==rest,代表这是这根长木棍第一次拼,更新一下longest的值。
num[now]++;
if(len==rest) break;
/*这个表示长木棍是第一次拼。
注意,目前这根短木棍now最终必然会属于一个长木棍。
如果第一次拼时不合法,说明这根短木棍所在的长木棍无法被拼出,可以直接结束 。*/
if(now==rest) break;
/*如果现在剩下rest,而且刚好有一根长度为rest的木棍,我肯定选它最优;
所以,如果试了它发现不成功,一定不会成功。*/
}
return 0;
} int main(){
// freopen("1120.in","r",stdin);
n=read();
for(int i=1;i<=n;i++){
in[i]=read();
if(in[i]<=50){
a[++t]=in[i];
sum+=a[t];
maxn=max(maxn,a[t]);
}
} if(!t){
printf("0\n");
return 0;
} for(int i=1;i<=t;i++)
num[a[i]]++;
for(int i=maxn;i<=sum;i++){
if(sum%i>0)
continue;
len=i; tot=sum/i;
if(dfs(1,len,maxn,maxn)){
ans=i;
break;
}
} printf("%d\n",ans);
return 0;
}