POJ 1011 Sticks
Posted lipeiyi520
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 1011 Sticks相关的知识,希望对你有一定的参考价值。
题目传送门
//原址有中文翻译
解题思路:
求出总长度sum和小棒最长的长度max,则原棒可能的长度必在max~sum之间,然后从小到大枚举max~sum之间能被sum整除的长度len,用dfs求出所有的小棒能否拼凑成这个长度,如果可以,第一个len就是答案。
下面就是关键的了,就是这道题dfs的实现和剪枝的设计:
1.以一个小棒为开头,用dfs看看能否把这个小棒拼凑成len长,如果可以,用vis[i]记录下用过的小棒,然后继续以另外一个小棒为开头,以此类推。
2.小棒的长度从大到小排序,这个就不解释了。
3.如果当前最长的小棒不能拼成len长,那么就返回前一步,更改前一步的最长小棒的组合情况(这里不能是全部退出),不用再继续搜索下去了。
4.最重要的,就是比如说17,9,9,9,9,8,8,5,2……如果当前最长小棒为17,它与第一个9组合之后dfs发现不能拼成len,那么17就不用和后面所有的9组合了,而直接和8开始组合。这个剪枝直接从TLE到16MS,很强大。
//转自http://blog.sina.com.cn/s/blog_6635898a0100lgq0.html
AC代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 6 using namespace std; 7 8 int n,a[70],ans; 9 bool flag,vis[70]; 10 11 bool cmp(int k,int b) 12 return k > b; 13 14 15 inline void dfs(int deep,int now,int i) 16 if(flag) return ; 17 if(now == 0) 18 int k = 0; 19 while(vis[k]) k++; 20 vis[k] = true; 21 dfs(deep + 1,a[k],k + 1); 22 vis[k] = false; 23 return ; 24 25 if(now == ans) 26 if(deep == n + 1) flag = true; 27 else dfs(deep,0,1); 28 return ; 29 30 for(int j = i;j <= n; j++) 31 if(!vis[j] && now + a[j] <= ans) 32 if(!vis[j-1] && a[j] == a[j-1]) continue; 33 vis[j] = true; 34 dfs(deep + 1,now + a[j],j + 1); 35 vis[j] = false; 36 37 38 39 40 int main() 41 42 while(true) 43 scanf("%d",&n); 44 if(n == 0) return 0; 45 flag = false; 46 int sum = 0; 47 for(int i = 1;i <= n; i++) 48 scanf("%d",&a[i]); 49 sum += a[i]; 50 51 sort(a + 1,a + n + 1,cmp); 52 for(ans = a[1];ans < sum; ans++) 53 if(sum % ans == 0) 54 memset(vis,0,sizeof(vis)); 55 dfs(0,0,1); 56 if(flag) break; 57 58 printf("%d\n",ans); 59 60 return 0; 61
以上是关于POJ 1011 Sticks的主要内容,如果未能解决你的问题,请参考以下文章