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