发现了两个可以剪枝的地方,不过看大神的博客说还有更多可以剪枝的地方,能到十多毫秒,给跪了。
我能写成这样已经很满足了,在剪枝之前,还是要先把深搜练熟练。祥见代码。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int M, b, flag;
int stick[30], book[30];
bool cmp(int a, int b) {
return a > b;
}
void dfs(int len, int num, int start) {
if(len == 0) {
if(num == 0) {
flag = 1;
}
else dfs(b, num - 1, 0);
}
else {
int i;
for(i = start; i < M && !flag; i++) { //flag = 1表示已经找到,也算是一个小优化吧
if(!book[i] && stick[i] <= len) { //此根棍一定不能比剩余的长度长。
book[i] = 1;
dfs(len - stick[i], num, i + 1);
book[i] = 0;
}
}
}
}
int main () {
//freopen("input.txt", "r", stdin);
int N;
scanf("%d", &N);
while(N--) {
flag = 0;
scanf("%d", &M);
int i, sum = 0;
for(i = 0; i < M; i++) {
scanf("%d", stick + i);
sum += stick[i];
book[i] = 0;
}
if(M < 4 || sum % 4 != 0) { //显然不能组成正方形
printf("no\n");
continue;
}
b = sum >> 2; //b为正方形的边长。
sort(stick, stick + M, cmp); //降序排序后能组成前三条边的种数就少了,可以少量优化时间
if(b < stick[0]) { //最长棍不能大于正方形边长
printf("no\n");
continue;
}
dfs(b, 3, 0); //由于是正方形,只需要搜出三条边就足够了
printf(flag ? "yes\n" : "no\n");
}
return 0;
}