从昨天晚上写到现在,一直在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 }