题目链接:http://poj.org/problem?id=1011
这个题目很经典,剪枝很巧妙,可以好好的研究一下,多做几次,很有价值;
#include<iostream> #include<string> #include<cstdio> #include<cstring> #include<queue> #include<map> #include<stack> #include<set> #include<vector> #include<algorithm> #define LL long long using namespace std; /* 枚举搜索,考察剪枝的使用,难度不低; */ vector<int>Length; // 动态数组; int L,N,LastStart; int vis[1005]; // 标记变量; int totalLength; // 所有棍子总长度; bool dfs(int R,int M) { if(R==0&&M==0) return true; // 说明刚好拼成几个完全一样的棍子 if(M==0) M=L; // 拼完成一根,开始拼下一根; int NowStart=0; // 剪枝4,从上一个棍子接着考虑的开始;从长木棍开始往下放; if(M!=L) NowStart=LastStart+1; for(int i=NowStart;i<N;i++){ if(!vis[i]&&Length[i]<=M){ // 当可以用这根棍子的时候; if(i>0) if(!vis[i-1]&&Length[i]==Length[i-1]) continue; // 剪枝1,在排好序的前提下,如果上一根和这个相同,且上一根不可用,那么显然这根也不可用; vis[i]=1;LastStart=i; if(dfs(R-1,M-Length[i])) return true; // 继续搜索; else{ vis[i]=0; if(Length[i]==M||M==L) return false; // 剪枝3,最后一根木棍等于这个长度,但是放失败了,那么其他棍子也是放不了替换也就没有什么意义了; // 剪枝2,一根棍子都没有放,但是已经有一个棍子被考虑了,说明就不可能用完所有的棍子; } } } return false; } int main() { while(~scanf("%d",&N)){ if(!N) break; Length.clear(); totalLength=0; for(int i=0;i<N;i++){ int a; scanf("%d",&a); Length.push_back(a); totalLength+=Length[i]; } sort(Length.begin(),Length.end(),greater<int>()); // 长度由长到短排序; for(L=Length[0];L<=totalLength/2;L++){ // 所有可能的长度枚举; if(totalLength%L) continue; // 说明不能拼成完整的这样长度的几根棍子; memset(vis,0,sizeof(vis)); if(dfs(N,L)){ printf("%d\n",L); break; } } if(L>totalLength/2) printf("%d\n",totalLength); // 说明只能拼成一个这样的棍子; } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/wlxsq/article/details/47001117