题目链接: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; }