题目链接:http://poj.org/problem?id=2362
题目大意:
有t组输入数据,每组数据一行;每行第一个为木棍根数(4<=n<=20),每根木棍长度(1<=stick<=10000)
判断能否拼成一个正方形
解析:
深搜剪枝:
剪枝:1、木棍数目小于4
2、总木棍长度/4=正方形边长不为整数
3、最大的木棍长度大于正方形边的长度
4、除1、2、3外,找到三条边即可
Code:
#include <iostream>
#include <algorithm>
using namespace std;
int n ;// 棍子数
int side; //矩形边长
int cmp(int a, int b) {
return a > b;
}
//stick为棍子长度数组,vis为标记数组, num表示已拼成边数, len为当前拼得的棍子总长度
//s为stick排序完后,起始数组下标
bool dfs(int *stick, bool *vis, int num, int len, int s) {
if(num == 3) //一旦找到三条边,第四条必定存在
return true;
for(int i=s; i<n; i++) {
//已访问过,将不再访问
if(vis[i])
continue;
vis[i] = true;
//总长度小于side,边数num不变,len = len+stick[i],边从下一条开始
if(len+stick[i] < side) {
//只有当最后一根找到,即第三条边找到,dfs()才会有返回True
if(dfs(stick, vis, num, len+stick[i], i))
return true;
}
//总长度等于side,边数num+1, len=0,s=0,重新进入下一条边的寻找
else if(len+stick[i] == side) {
//只有当最后一根找到,即第三条边找到,dfs()才会有返回True
if(dfs(stick, vis, num+1, 0, 0))
return true;
}
vis[i] = false;
}
return false;
}
int main(void) {
int time;
//freopen("2.in", "r", stdin);
//freopen("2.out", "w", stdout);
cin >> time;
while(time--) {
int sum = 0;
cin >> n;
int stick[21];
bool vis[21];
int maxside = 0;
for(int i=0; i<n; i++) {
cin >> stick[i];
vis[i] = false;
if(maxside < stick[i])
maxside = stick[i];
sum += stick[i];
}
//剪枝1、棍子小于4根,边长不是整数,最长棍子比边还长
if(n<4 || sum%4 || maxside>sum/4) {
cout << "no" << endl;
continue;
}
sort(stick, stick+n, cmp);
side = sum / 4;
if(dfs(stick, vis, 0, 0, 0))
cout << "yes" << endl;
else
cout << "no" << endl;
}
return 0;
}