- 解题思路,搜索时从小到大枚举原木棍长度,显然(木棍最大长度≤原木棍长度≤木棍总长度),然后搜索判断情况能否可行。
- 然后就来说说最最重要的剪枝吧:
- 1、优化顺序,dfs判断情况时从最长的木棍枚举到最短的木棍,因为能与最长的木棍组成当前需要的长度的木棍的个数显然要比长度短的少,能减少分枝数。因为长度不超过50,于是没必要对木棍长度快排,而是直接桶排,常数小且方便判断和回溯。
- 2、木棍个数应该为整数,所以枚举的长度应该能整除总长度。
- 3、若当前搜索时已经使用了长度为x的木棍,则下次直接从长度为x从大到小枚举,因为显然比x长的都不可行了,否则当前就不会使用x了。
- 4、若某次搜索拼接时,当前拼好的长度为0或当前长度加上先前枚举的长度等于需要长度,直接跳出循环,因为我们是递减枚举,显然再往后搜不能再从那些长度小的木棍中拼出当前的长度。
-
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define maxn 99 int n,maxx,lw,sum,x,dp[maxn]; void dfs(int num,int now,int len,int up) { if(num==0) { printf("%d\n",len); exit(0); } if(now==len) { dfs(num-1,0,len,maxx); return; } for(int i=up; i>=lw; i--) { if(now+i<=len&&dp[i]>0) { dp[i]--; dfs(num,now+i,len,i); dp[i]++; if(!now||now+i==len)break; } } return; } int main() { lw=inf; maxx=sum=0; scanf("%d",&n); while(n--) { scanf("%d",&x); if(x>50)continue; dp[x]++; lw=min(x,lw); maxx=max(maxx,x); sum+=x; } x=sum>>1; for(int i=maxx; i<=x; i++) { if(sum%i==0) dfs(sum/i,0,i,maxx); } printf("%d\n",sum); return 0; }