UVa 307 - Sticks
Sticks |
【 随 笔 】:很久之前就遇到这道题,题目意思容易理解,后来自己想到了一个法子,思路也很清晰就将代码敲出来了,用了位运算(后来问师兄是说状态压缩,其实我不知道什么是状态压缩~_~),不过提交的时候超时了,我想着优化代码,尽可能加剪枝的条件,却无从下手,后来搜题解搜到了师兄的博客,题解中剪枝的条件自己能想到的五个中了三个,剩下两个剪枝也容易理解,整个DFS的思路也容易理解,这点值得反思,其中的原因我想是自己先入为主了,在之前的思路上瞎折腾,未果却也不接受考虑另外的可能,其实看了师兄的代码思路后,也就是普普通通的暴力回溯,不多说,先保存TL的代码:
【AC的代码链接】:http://www.cppblog.com/y346491470/articles/155318.html
【超时的代码】
1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #define MAXN 500 6 using namespace std; 7 int sticks[MAXN]; 8 bool visit[MAXN]; 9 int n, sumlen, res; 10 11 bool judge(int fac) 12 { 13 int i; 14 for(i=0; i<n && visit[i]; ++i); 15 if(i<n) return false; 16 else 17 { 18 res = fac; 19 return true; 20 } 21 } 22 23 bool Traverse(int fac) 24 { 25 for(int i=0; i<(1<<n); ++i) 26 { 27 int subsum = 0; 28 bool is_useful = true; 29 for(int k=0; k<n; ++k) 30 { 31 if(i&(1<<k)) 32 { 33 if(visit[k] || subsum > fac) 34 { 35 is_useful = false; 36 break; 37 } 38 else subsum += sticks[k]; 39 } 40 } 41 if(is_useful && subsum == fac) 42 { 43 for(int k=0; k<n; ++k) 44 { 45 if(i&(1<<k)) visit[k] = true; 46 } 47 if(judge(fac) || Traverse(fac)) return true; 48 for(int k=0; k<n; ++k) 49 { 50 if(i&(1<<k)) visit[k] = false; 51 } 52 } 53 } 54 return false; 55 } 56 57 int main() 58 { 59 #ifndef ONLINE_JUDGE 60 freopen("F:\\test\\input.txt", "r", stdin); 61 #endif // ONLINE_JUDGE 62 while(cin>>n, n) 63 { 64 int curmax = 0; 65 sumlen = 0; 66 for(int i=0; i<n; ++i) 67 { 68 cin>>sticks[i]; 69 curmax = curmax > sticks[i] ? curmax :sticks[i]; 70 sumlen += sticks[i]; 71 } 72 for(int fac = curmax; fac <= sumlen; ++fac) 73 { 74 if(sumlen%fac == 0) 75 { 76 memset(visit, false, sizeof(visit)); 77 if(Traverse(fac)) 78 { 79 cout<<res<<endl; 80 break; 81 } 82 } 83 } 84 } 85 86 return 0; 87 }
自己后来又重新写了一遍,写的过程中感觉还是对回溯的理解还是不够深,回溯本是暴力的一种,所以这题也能看到一层一层搜索的路径,没有太多的技巧,都是根据题目的特性找规律,充分利用从而写出剪枝的条件,避免了超时,效率也更高。
【AC代码】
1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #include<algorithm> 6 #define MAXN 1000 7 8 using namespace std; 9 10 int sticks[MAXN]; 11 bool visit[MAXN]; 12 int n, length, sum, sumlen; 13 14 bool cmp(const int& a, const int& b) 15 { 16 return a>b; 17 } 18 19 bool Traverse(int num, int len, int cur) 20 { 21 if(num == sum) return true; 22 for(int i=cur; i<n; ++i) 23 { 24 if(!visit[i] && !(i && !visit[i-1] && sticks[i] == sticks[i-1])) 25 { 26 if(len+sticks[i] == length) 27 { 28 visit[i] = true; 29 if(Traverse(num+1, 0, 0)) return true; 30 visit[i] = false; 31 return false; 32 } 33 else if(len+sticks[i] < length) 34 { 35 visit[i] = true; 36 if(Traverse(num, len+sticks[i], i+1)) return true; 37 visit[i] = false; 38 if(len == 0) return false; 39 } 40 } 41 } 42 return false; 43 } 44 45 46 int main() 47 { 48 #ifndef ONLINE_JUDGE 49 freopen("F:\\test\\input.txt", "r", stdin); 50 #endif // ONLINE_JUDGE 51 while(cin>>n, n) 52 { 53 int curmax = 0; 54 sumlen = 0; 55 for(int i=0; i<n; ++i) 56 { 57 cin>>sticks[i]; 58 sumlen += sticks[i]; 59 } 60 sort(sticks, sticks+n, cmp); 61 for(int fac = sticks[0]; fac <= sumlen; ++fac) 62 { 63 if(sumlen%fac == 0) 64 { 65 length = fac; 66 sum = sumlen/fac; 67 memset(visit, false, sizeof(visit)); 68 if(Traverse(0,0,0)) break; 69 } 70 } 71 cout<<length<<endl; 72 } 73 74 return 0; 75 }
更多内容请关注个人微信公众号 物役记 (微信号:materialchains)
作者:雪影蓝枫
本文版权归作者和博客园共有,欢迎转载,未经作者同意须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。