Fork me on GitHub

UVa 307 - Sticks

Sticks 

【题目链接】:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=243

【 随 笔 】:很久之前就遇到这道题,题目意思容易理解,后来自己想到了一个法子,思路也很清晰就将代码敲出来了,用了位运算(后来问师兄是说状态压缩,其实我不知道什么是状态压缩~_~),不过提交的时候超时了,我想着优化代码,尽可能加剪枝的条件,却无从下手,后来搜题解搜到了师兄的博客,题解中剪枝的条件自己能想到的五个中了三个,剩下两个剪枝也容易理解,整个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 }

 

posted @ 2013-07-11 01:06  Gifur  阅读(477)  评论(0编辑  收藏  举报
TOP