题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1518
题目描述:给出若干个破木头条子。问你它们能否拼成一个正方形。
解题思路:
一道DFS题,DFS是我软肋啊。不过经过这道题,算是找到一种固定模式了,以后遇到DFS题就不会不知♂所措。
解释一下我DFS函数中的变量 len 和 dep,分别表示手里拿的木棍总长,每当达到一个边长就放下这些木棍(并标记),再从头开始找,dep表示已找到的边长数量,显然找到 4 个就能构成正方形。
交上去T了。
所以我们再考虑剪枝,问题出在我写的基本上是一个生成全排列的DFS,而这道题显然不用考虑顺序,所以每次不用从 1 开始搜,加入一个 from 变量记一下位置,下次接着搜就好了,也就是说 “排列” 和 “组合” 是不同的。这样就AC了。
我还在想,那是不是不需要 use 数组了,去掉是 WA 的,因为在你凑齐一个边长并放下手里木棍时候必须标记好用过哪些,再找的时候才是对的。
AC代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int arr[30],use[30];
int num,sum,found;
void dfs(int from,int len,int dep)
{
if(!found&&len<=sum/4)
{
//cout<<len<<" "<<dep<<endl;
int i;
if(len==sum/4)
{
if(dep==4)
found=1;
else
dfs(1,0,dep+1);
}
else
{
for(i=from;i<=num;i++)
{
if(!use[i])
{
use[i]=1;
dfs(i+1,len+arr[i],dep);
use[i]=0;
}
}
}
}
}
int main()
{
//freopen("1518_input.txt","r",stdin);
int T,i;
scanf("%d",&T);
while(T--)
{
scanf("%d",&num);
sum=0;found=0;
memset(arr,0,sizeof(arr));
memset(use,0,sizeof(use));
for(i=1;i<=num;i++)
{
scanf("%d",&arr[i]);
sum+=arr[i];
}
if(sum%4!=0)
{
printf("no\n");
}
else
{
dfs(1,0,1);
if(found)
printf("yes\n");
else
printf("no\n");
}
}
return 0;
}
AC截图: