来源:http://poj.org/problem?id=2362
题意:给你一些木棍,判断能不能用这些木棍围城一个正方形。注意是所有的木棍都要用到,且每个木棍只能用一次。
思路:数据范围不大,n是小于20的,所以明显可以用dfs。主要有三个剪枝的地方,1:所有木棍的长度和必须为4的倍数,否则的话,肯定围不成正方形;2:设正方形的变长为side,则所有木棍中的最大长度maxlen必须小于等于side,否则也围不成正方形;3:搜索边时,当有一条边围不成正方形时,就可以退出dfs了,直接输出no即可。三个剪枝就可以把这道题过了。
代码:
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
#define CLR(arr,val) memset(arr,val,sizeof(arr))
const int N = 25;
int num[N],flag[N],sum,side,n;
bool isok;
void init(){
CLR(num,0);
CLR(flag,0);
sum = 0;
side = 0;
isok = false;
}
void dfs(int begin,int len,int cnt){
if(cnt == 3){
isok = true;
return;
}
if(len == side){
dfs(0,0,cnt+1);
}
if(isok) return;
for(int i = begin; i < n; ++i){
if(!flag[i] && len + num[i] <= side){
flag[i] = true;
dfs(i+1,len + num[i],cnt);
if(isok) return;
flag[i] = false;
}
}
}
bool cmp(int a,int b){
return a > b;
}
int main(){
//freopen("1.txt","r",stdin);
int numcase;
scanf("%d",&numcase);
while(numcase--){
init();
scanf("%d",&n);
int maxlen = 0;
for(int i = 0; i < n; ++i){
scanf("%d",&num[i]);
sum += num[i];
if(num[i] > maxlen)
maxlen = num[i];
}
sort(num,num+n,cmp);
if(sum % 4 || 4 * maxlen > sum){
printf("no\n");
continue;
}
side = sum / 4;
isok = false;
dfs(0,0,0);
if(isok)
printf("yes\n");
else
printf("no\n");
}
return 0;
}