题意:某人把若干等长的木棒 随机的切成小段 现在给你这些小段 求原来等长的木棒的最小可能值
用DFS来搜索木棒的组合
其中的一个最重要的剪枝为: 在构造原始木棒时,我们考虑的第一根木棒(设下标为i)不能构造成功,那么这个原始木棒的长度就是错误的答案。假设我们用i之后的一个木棒k为原始木棒的第一个成功了。那么在构造下一个原始木棒时,我们一定同样会以第I个小木棒为起点来搜索,由上一次的搜索结果我们得知,i作为起点是不能构成一个木棒的。但由我们的组合方式可以看到,如果此时的原始木棒是正解,i一定是某个原始木板的起点小木棒,这与我们得知的信息,以i为起点不能构造一个小木棒矛盾,所以这个原始木棒的解是错误的,我们在此退出DFS搜索。
如何利用之前得到的信息,来为去掉后面多余的计算步骤是很有必要的。
代码如下:
#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#include <algorithm>
#define sf scanf
#define pf printf
using namespace std;
const int maxn = 100;
int sticks[maxn];
bool vis[maxn];
int initLen;
int n;
bool DFS(int cur,int len,int used_stick){
if(len == 0){ //构造完一个木棒
if(used_stick == n){ //所有的part都用完
return true; //这个initLen是正确的
}
int k = 0; //还有part没有用
while(vis[k]) ++k; //找到最大的一个没有用的part
if( DFS(k,initLen,used_stick) ){ //从最大的part开始构造一个长度为initLen的木棒
return true; //成功用剩下的part构造了若干个长度为initLen的木棒
}else return false; //失败
}
else if(cur == n || used_stick == n) return false; //遍历完所有的part没有构造一个长度为initLen的木棒 或者 用完了全部木棒 不能全部构造若干个长度为initLen的木棒
else{
for(int i = cur;i < n;++i){ //从cur处开始构造
if(!vis[i] && sticks[i] <= len){ //第i个part小于等于len
// pf("%d\n",)
vis[i] = 1;
if( DFS(i + 1,len - sticks[i],used_stick + 1) ){ //构造成功 返回true
return true;
}
else{
vis[i] = 0;
if(sticks[i] == len) break;
int temp = sticks[i]; //失败 找到下一个不等于stick[i]的part
while(temp == sticks[i] && i < n) i++;
if(i == n) return false;
else i--;
}
if(len == initLen) break; //剪枝4 最重要的剪枝
}
}
return false;
}
}
int main(){
// freopen("out.txt","w",stdout);
while( sf("%d",&n) && n ){
int max_len = 0,sum_len = 0;
for(int i = 0;i < n;++i) sf("%d",&sticks[i]),sum_len += sticks[i];
sort(sticks,sticks + n,greater<int>());
max_len = sticks[0];
for(initLen = max_len;initLen < sum_len;++initLen){
if(sum_len % initLen == 0){
// pf("------------------------%d\n",initLen);
memset(vis,0,sizeof(vis));
if(DFS(0,initLen,0)) break;
}
}
printf("%d\n",initLen);
}
return 0;
}