题目链接: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; }