(HDU - 1518)Square
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 16247 Accepted Submission(s): 5120
Problem Description
Given a set of sticks of various lengths, is it possible to join them end-to-end to form a square?
Input
The first line of input contains N, the number of test cases. Each test case begins with an integer 4 <= M <= 20, the number of sticks. M integers follow; each gives the length of a stick - an integer between 1 and 10,000.
Output
For each case, output a line containing “yes” if is is possible to form a square; otherwise output “no”.
Sample Input
3
4 1 1 1 1
5 10 20 30 40 50
8 1 7 2 6 4 4 3 5
Sample Output
yes
no
yes
题目大意:给出n根木棒,问这n根木棒能都构成正方形,所有木棒都要用到。
思路:dfs+剪枝。dfs需要回溯,因为标记后,如果那种方法不行,回溯才能使下次能搜到这些之前被标记过但这次还需要再搜的边。信仰剪枝,大胆暴力出奇迹….当时没怎么想,就是一发暴力,结果900ms爬过…
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=25;
int a[maxn];
bool vis[maxn];
int m,avelen;
bool dfs(int cnt,int tmplen,int id)//cnt表示已经成功的边数,tmplen表示当前边的长度,id表示当前所用棍子编号
{
if(cnt==4) return true;
if(tmplen==avelen)
{
if(dfs(cnt+1,0,0)) return true;
}
for(int i=id;i<m;i++)
if(!vis[i]&&tmplen+a[i]<=avelen)
{
vis[i]=1;
if(dfs(cnt,tmplen+a[i],i+1)) return true;
vis[i]=0;//回溯
}
return false;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&m);
int sumlen=0;
for(int i=0;i<m;i++)
{
scanf("%d",a+i);
sumlen+=a[i];
}
avelen=sumlen/4;
sort(a,a+m);
if(sumlen%4||a[m-1]>avelen)//不能被4整除或者最长的木棒比边长还长,则不能构成正方形
{
printf("no\n");
continue;
}
memset(vis,0,sizeof(vis));
bool flag=dfs(0,0,0);
if(flag) printf("yes\n");
else printf("no\n");
}
return 0;
}