小木棍
Posted fangbozhen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小木棍相关的知识,希望对你有一定的参考价值。
题目描述
有N根小木棍,他们有各自的长度,若它们能拼成整数多的len长的木棍,求len的最小值。
思路
从题目上看,一个显然的思路是我们可以暴力从小到大枚举len,用dfs看能否拼成这么多木棍。不过裸的dfs肯定T飞了,我们尝试进行优化。
首先从可行性方面进行优化,我们提出五种剪枝:
①一根长木棍用处肯定比用几根短木棍拼成相同长度的作用小,所以我们可以把木棍从大到小排序。
②我们按照这个顺序依次处理每一根木棍,那么显然到第i个木棍时,只能从i+1开始寻找,因为前面的都已用过。
③相同长度的木棍不用搜索多次,可以直接处理。对于找不到时可直接返回。
④判断当前木棍的长度能否拼成len长木棍,不能就直接返回。
⑤找到答案立刻返回。
我们再从最优性方面做出两种剪枝:
⑥设所有木棍长为sum,那我们枚举的len一定能被len整除。
⑦len一定大于等于剩余木棍中最长的。
代码
#include <bits/stdc++.h> using namespace std; int m,n,len,used[70],a[70]; bool f; bool cmp(int x,int y) { return x>y; } void dfs(int k,int last,int rest) { int i; if(f)return ; //剪枝⑤ // cout<<k<<‘ ‘<<rest<<endl; if(k==m){f=1;return ;} if(rest==0) { for(i=1;i<=n;i++) if(!used[i])break ; used[i]=1; dfs(k+1,i,len-a[i]); used[i]=0; } for(i=last+1;i<=n;i++) //剪枝② if(!used[i]&&a[i]<=rest) { used[i]=1; dfs(k,i,rest-a[i]); used[i]=0; int j=i; while(i<n&&a[i]==a[j])i++; //剪枝③ if(i==n)return ; } } int main() { int sum=0,minn=0; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum+=a[i]; minn=max(a[i],minn); // cout<<minn<<endl; } sort(a+1,a+n+1,cmp); //剪枝① /* for(int i=1;i<=n;i++) printf("%d ",a[i]); printf(" ");*/ // cout<<sum<<endl; for(int i=minn;i<=sum;i++) //剪枝⑥ if(sum%i==0) //剪枝⑤ { // cout<<i<<endl; memset(used,0,sizeof(used)); f=0;used[1]=1; len=i;m=sum/i; dfs(1,1,len-a[1]); if(f){printf("%d",i);break ;} } return 0; }
以上是关于小木棍的主要内容,如果未能解决你的问题,请参考以下文章