这道题我想了很久,一直想不出来…… 是看了师兄的解题报告 仔细研究了很久才有点明白的 #include <stdio.h> #include <stdlib.h> #define NUM 21 int n,l[NUM],sum,used[NUM],edge,find; int cmp(const void *a,const void *b) { return *(int *)b-*(int *)a; } void dfs(int cur,int curlen,int m); void square(int m)// 如果进入这个函数 有两种可能 一种是从主函数进入 另一种是从dfs 进入 如果从dfs进入 就证明已经成功的构造了一条边 但是 不证明这样的进入会有什么结果 { if(find==1)return;//是退出的第一个端口 if(m==1) { find=1; return;// 和上一句的功能不太一样,这一句是 } else { int i=0; for(;i<n;i++) if(!used[i])break;//找到第一个没有使用过的木条 每次都按照一样的顺序去查找 免去了重复的步骤 used[i]=1; dfs(i,l[i],m); used[i]=0;//如果走到这一步,证明现在的木棍不能和之前一同构成边,也就是要从此再次回溯到上一个边 对下一种可能进行判断,也很重要 } return; } void dfs(int cur,int curlen,int m) { if(find==1)return;//中途递归时防止进步调用函数返回 if(curlen==edge) { square(m-1); return; } else { for(int i=cur+1;i<n;i++) //从当前进入木棒的下一个开始查找 if(!used[i]) { if(curlen+l[i]<=edge) { used[i]=1; dfs(i,curlen+l[i],m); used[i]=0;//此处至关重要,像是二叉树的回溯,如果此处构不成 那么就将检查它的下一处 同时将它的标记归零 } } } } int main() { int test; scanf("%d",&test); while(test--) { scanf("%d",&n); sum=0; for(int i=0;i<n;i++) { scanf("%d",&l[i]); sum+=l[i]; used[i]=0; } if(sum%4!=0)printf("no/n"); else { qsort(l,n,sizeof(l[0]),cmp); edge=sum/4; if(edge<l[0])printf("no/n"); else { find=0; square(4); if(find==1)printf("yes/n"); else printf("no/n"); } } } return 0; }