【深度搜索+剪枝】POJ2362-Square

从昨天晚上写到现在,一直在TLE,现在终于剪枝完成了_(:зゝ∠)_

【思路】

深搜:用这类型组合题目最基本的深搜,变量side记录当成已经组成了几条变,sl表示当前在组合的边已经有的长度。如果当前stick的长度与已有长度的和恰巧等于边长,则side+1,将sl清零;否则若小于边长,则sl+当前长度继续搜索,直到组成所有边为止。

剪枝:(1)如果木棒数目没有到达四根,则为no

     (2)比较容易想到的一点,如果当前木棒总长不是4的整数倍,则为no

   (3)由于木棒不能这段,如果最长的木棒大于边长,则为no

   (4)由于越短的木棒灵活性越高,进行快排之后由大至小进行搜索。

   (5)为了避免重复搜索,我们默认组成同一边时,下一根取的木棒长度必定不大于当前根的木棒。故设置变量frm,即当前可取木棒长度的范围。

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int MAXN=20+10;
 7 int stick[MAXN];
 8 int n,sum,m; 
 9 bool visited[MAXN];
10 
11 bool dfs(int frm,int side,int sl)
12 {
13     if (3==side) return(true);
14     for (int i=frm;i>=0;i--)
15         if (!visited[i])
16         {
17             visited[i]=true;
18             if (stick[i]+sl<sum)
19             {
20                 if (dfs(i-1,side,sl+stick[i])) return true;
21             }
22             else
23                 if (stick[i]+sl==sum)
24                 {
25                     if (dfs(m-1,side+1,0)) return true;
26                 }
27             visited[i]=false;
28         }
29     return false;
30 }
31 
32 int main()
33 {
34     scanf("%d",&n);
35     for (int kase=0;kase<n;kase++)
36     {
37         memset(visited,false,sizeof(visited));
38         scanf("%d",&m);
39         sum=0;
40         int max=-1;
41         for (int i=0;i<m;i++) 
42         {
43             scanf("%d",&stick[i]);
44             sum+=stick[i];
45             if (stick[i]>max) max=stick[i];
46         }
47         if (sum%4!=0||m<4||max>sum/4) cout<<"no"<<endl;
48         else
49         {
50             sort(stick,stick+m);
51             sum=sum/4;
52             if (dfs(m-1,0,0)) cout<<"yes"<<endl;
53             else cout<<"no"<<endl;
54         }
55     }
56     return 0;
57 }

 

posted @ 2015-07-04 11:55  iiyiyi  阅读(664)  评论(0编辑  收藏  举报