传送门:Square
Square
Source : Waterloo ACM Programming Contest Sep 21, 2002 | |||
Time limit : 1 sec | Memory limit : 32 M |
Submitted : 522, Accepted : 180
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 5Sample Output
yes no yes
解题报告:
此题和HOJ1049/POJ1011/HDOJ1049 sticks的剪枝方法一样。
首先没看清题目,以为只要组成一个四边形就可以,然后就直接写了,然后样例给的也不特殊嘛,然后交了几次都是WA。
然后看了很久代码,发现当前面一根没被访问过,如果后面那根长度和前面一样,那么也不需要访问,而这个至少把时间从760ms提高到6ms。但是还是WA。
重新审阅题目后发现,要求所有的都要使用能组成一个四边形才行,顿时恍然大悟。修改后,终于AC
代码如下:
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int sum; //总和
int square[30];//储存边
int l;//四边形每条边的长度
bool visited[30]; //标记访问
bool flag; //标记是否有解
int n;
bool cmp(int a,int b){
return a>b;
}
bool dfs(int s,int slen,int pos){ //s当前已经分配好的边,slen当前总长度,pos当前第几条边
if(s==4)
return true;
bool sign =(slen==0?true:false);
for(int i=pos+1;i<n;i++){
if(visited[i]==true)
continue;
if(square[i]==square[i-1]&&!visited[i-1])
continue;
if(slen+square[i]==l){
visited[i]=true;
if(dfs(s+1,0,-1))
return true;
else{
visited[i]=false;
return false;
}
}
else if(slen+square[i]<l){
visited[i]=true;
if(dfs(s,slen+square[i],i))
return true;
else{
visited[i]=false;
if(sign)
return false;
}
}
}
return false;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
sum=0;
flag=false;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&square[i]);
sum+=square[i];
}
sort(square,square+n,cmp);
memset(visited,0,sizeof(visited));
if(sum%4==0){
l=sum/4;
if(dfs(1,0,-1))
flag=true;
}
if(!flag)
printf("no\n");
else
printf("yes\n");
}
return 0;
}