问题重述:
给定一堆不定长度的木棍,问他们能否构成一个正方形。
题目传送门:点击打开链接
解题思路:
DFS +剪枝
剪枝条件1 :最长的木棍不能比正方形的边长长;
剪枝条件2:木棍总长度必须被4整除
剪枝条件3:如果第3条边被确定,那就肯定可以构成正方形
/** DFS + 剪枝 **/
#include <stdio.h>
#include <stdlib.h>
int cmp(const void *elem1,const void *elem2) //排序准备函数
{
return *(int *)elem2 - *(int *)elem1;
}
int side; //正方形的边长
int n; //木棍数量
int sticks[100]; //存放木棍长短的数组
bool visited[100]; //访问标志数组
//num 已组合的正方形的边数
//len 当前组合的边的组合长度
//s 搜索起点
bool dfs(int *sticks,bool *visited,int num,int len,int s) //深搜函数
{
if(num==3) //剪枝条件3 ,3条边都组合好
return true;
for(int i=s; i<n; i++) //开始搜索
{
if(visited[i]) //如果已经访问,跳过
continue;
visited[i] = true;
if(len+sticks[i]<side) //不够长
{
if(dfs(sticks,visited,num,len+sticks[i],i)) //向下递归继续找
return true;
}
else if(len+sticks[i]==side) //刚好能组成一条边
{
if(dfs(sticks,visited,num+1,0,0)); //那就构建一条边
return true;
}
visited[i] = false; //更新访问标志
}
return false;
}
int main()
{
//freopen("in.txt","r",stdin);
int t; //数据次数
scanf("%d",&t);
for(int i=0; i<t; i++)
{
scanf("%d",&n);
int sum = 0;
for(int j =0; j<n; j++)
{
scanf("%d",&sticks[j]); //输入每组数据的木棍长度
visited[j] = false; //初始化
sum += sticks[j]; //求木棍总长度
}
if(n<4||sum%4!=0) //剪枝条件2 总长不能被4整除
{
printf("no\n");
continue;
}
qsort(sticks,n,sizeof(int),cmp); //降序排列
side = sum/4;
if(sticks[0]>side) //剪枝条件,1,最长的木棍比边长长
{
printf("no\n");
continue;
}
if(dfs(sticks,visited,0,0,0)) //全部木棍构建完毕
printf("yes\n");
else
printf("no\n");
}
return 0;
}