AcWing 167. 木棒
考察:dfs+剪枝
思路:
写dfs先定搜索顺序,很明显我们需要枚举和,一共64个木棒,如果暴力枚举是264,必然TLE,因此在枚举和时就需要优化.可以发现如果这些木棒能拼成等长的大木棍,那么所有木棒的和一定是大木棍的倍数.由此我们只需要枚举sum的约数.定下搜索顺序后,就是将木棒分成等长的x组的问题.
再考虑剪枝,首先要选分支少的,很明显拼接首先选长的,所有将所有木棒进行从大到小排序.
其次要去除冗余情况,很明显这里是组合性枚举.还有如果当前长度为s的配对失败,后面长度为s的也不用配对.
最优性剪枝,将答案从小到大枚举.
最后两个剪枝很难想:
- 当我们拼接大木棍的第一个木棒不成功时(没有能与该木棒配对的,或者在后面难以配对),直接返回上一个分支.因为木棒是从大到小开始枚举的.
2.当我们拼接大木棍的最后一个木棒不成功时,也是直接返回上一个分支,不需要枚举.这里的不成功有两种情况:
- 没有能与正在拼接的木棍配对的,此方案一定错误.
- 有能配对的,此方案不成功说明后面配对失败.我们假设当前木棒s配对失败,根据枚举我们会以>1的小木棒(和为s)代替木棒s.但是此替换与直接放s没有区别,所以直接return
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 using namespace std; 6 const int N = 70; 7 int n,a[N],cnt,ans,m; 8 bool st[N]; 9 struct cmp{ 10 bool operator()(int x,int y) 11 { 12 return x>y; 13 } 14 }; 15 bool dfs(int p,int len,int start) 16 { 17 if(p>=cnt) return 1; 18 if(len==ans) return dfs(p+1,0,1); 19 int fall = 0; 20 for(int i=start;i<=m;i++) 21 { 22 if(!st[i]&&a[i]+len<=ans&&fall!=a[i]) 23 { 24 st[i] = 1; 25 if(dfs(p,len+a[i],i+1)) return 1; 26 st[i] = 0; 27 fall = a[i]; 28 if(!len||len+a[i]==ans) return 0; 29 } 30 } 31 return 0; 32 } 33 int main() 34 { 35 while(scanf("%d",&n)!=EOF&&n) 36 { 37 int sum = 0,x; m = 0; 38 for(int i=1;i<=n;i++) 39 { 40 scanf("%d",&x); 41 if(x>50) continue; 42 a[++m] = x; 43 sum+=x; 44 st[i] = 0; 45 } 46 sort(a+1,a+m+1,cmp()); 47 ans = a[1]; 48 while(ans<=sum) 49 { 50 if(sum%ans==0) 51 { 52 cnt = sum/ans; 53 if(dfs(0,0,1)) {printf("%d\n",ans);break;} 54 } 55 ans++; 56 } 57 } 58 return 0; 59 }