POJ_1011_Sticks

////搜索剪枝,一个好的剪枝真的是太关键了,对剪枝有了进一步了解 ///先深度搜索出一只原始木棍,将用到的小木棍标识为已经使用,在这个基础上再深度搜索下 ///一只原始木棍,分层深度搜索(自己想的名字),最后根据是否得到了目标数目的原始木棍来判断 ///程序是否结束。 #include<stdio.h> #include<string.h> #include<algorithm> #include<time.h> using namespace std; int f[70],stick[70]; int n,t,flag; int cmp(const void* _a,const void* _b) { int* a=(int *)_a; int* b=(int *)_b; return -(*a-*b); } //ti:已经组合成长度p的木棍的数目。total:已匹配的小木棍加起来的长度,begin:下一根小木棍 //从何处开始匹配。 int dfs(int ti,int p,int total,int begin) { //flag为1则表示已经成功匹配了所有小木棍,并能够得到结果。 if(ti==t) { flag=1;return 1; } if(flag) return 1; int i,j,last; //剪枝3:last保存本次循环(不会传到子函数中)中上次处理的木棍长度,主要是避免相同长度的木棍 //重复问题 for(i=begin,last=-1;i<n;i++) { if(!f[i]&&stick[i]!=last) { if(stick[i]<p-total) { last=stick[i]; f[i]=1; dfs(ti,p,total+stick[i],i+1); f[i]=0; } if(stick[i]==p-total) { last=stick[i]; f[i]=1; dfs(ti+1,p,0,0); f[i]=0; } if(flag) return 1; ///缺少了下面的判断要多出很多不必要的计算,相当关键 /***************************/ if(begin==0) return 0; /***************************/ } } return 0; } ///判断是否能够组合成数根原始长度为p的木棍,能返回1,否则返回0 int isok(int p) { memset(f,0,sizeof(f)); flag=0; if(dfs(0,p,0,0)) return 1; else return 0; } //n为木棍数目,stick[]存储的是木棍长度,sum所有木棍总长度 int main() { freopen("in.txt","r",stdin); freopen("ou2.txt","w",stdout); while(scanf("%d",&n)==1&&n) { int i,sum=0; for(i=0;i<n;i++) { scanf("%d",&stick[i]); sum+=stick[i]; } //剪枝1:木棍由大到小排列,长度大的木棍比长度小的木棍更有用,可以减少搜索深度 qsort(stick,n,sizeof(stick[1]),cmp); for(i=stick[0];;i++)///initial最小长度为所给木棍的最大长度 { t=sum/i;///t保存原始木棍的数目 ///剪枝2:木棍总长度必为原始木棍长度的倍数 if(sum%i==0&&isok(i)) break; } printf("%d %f/n",i,(double)clock()/CLOCKS_PER_SEC); } return 0; }

你可能感兴趣的:(POJ_1011_Sticks)