题目链接:http://poj.org/problem?id=2362
这道题和poj1011大致是一个意思,但是我用那道题的代码直接改来交上去却超时了,只能说明1011题的测试数据弱了,在这道题上,还可以有两个比较大的剪枝:
一、需要拼成正方形,只要拼成三条边,就可以判断能否拼成正方形了!
二、对数据的降序排列,为了减少重复设置搜索起点,即如果剩余的边需拼成的长度大于本身棒的长度,则下次开始搜索的时候就直接从该棒开始而不用从头开始了!
下面的代码是我在1011题的基础上更改的,写的很不好,没有纯粹的写一道题的程序出来更简洁,不过人懒了,改改也过了!
#include<iostream>///找最小的长度的
#include<algorithm>
using namespace std;
int stick[70],n,sign;
bool vis[70];
int cmp(const void *a,const void *b)
{
return *(int *)b-*(int *)a;
}
int fun(int i,int m,int t,int begin)//需要匹配的长度,已经匹配的段数,这一小段还需要的长度
{
int j;
if(t==0 && m==n)//一个段都已经匹配完了
{
sign=1;
return i;
}
if(t==0)
t=i;
for(j=begin; j<n; j++)
{
if(vis[j]==false)//就是可以的
{
vis[j]=true;
if(stick[j]<t)
{
if(fun(i,m+1,t-stick[j],j))
return i;//不然就继续走了
}
if(stick[j]==t)
{
if(fun(i,m+1,t-stick[j],0))
return i;//不然就继续走了
}
vis[j]=false;
if(t==i || t==stick[j])//似乎明白了,如果t==i的话则找不到一个和它匹配的棍子的,
break;
while(stick[j]==stick[j+1])
j++;
}
}
return 0;
}
int main()
{
int i,j,k,sum,m;
scanf("%d",&m);
while(m--)
{
sign=0;
sum=0;
scanf("%d",&n);
for(i=0; i<n; i++)
{
scanf("%d",&stick[i]);
sum+=stick[i];
vis[i]=false;
}
qsort(stick,n,sizeof(int),cmp);//降序排列的
fun(sum/4,0,sum/4,0);//返回的不是1
if(sign==1)
printf("yes\n");
else
printf("no\n",i);
}
return 0;
}