给你m个长。第一道剪枝的搜索,给你一些棍子,
把这些棍子分成k份,问每份的最小长度
可以是一份,所以每份的最大长度就是sumO(∩_∩)O哈哈~
但是问的是最小长度,方法是dfs搜索。
策略是用一个记录合成的棍子数目,另一个是合成的长度
最后一个。
两种写法
注意1 用了灰常灰常牛逼的回溯,所以每次不用初始化数组咯。
(自己领悟)
2 两处剪枝,一处剪枝其实就是让大家就地解散的意思。
一处是有一个串没用到,相同的也不用了。去也一个德行。另一处
如果有一个第一次都没用到,那么他肯定会被舍弃。
说明他一个已经比要组成的大了,大家就地解散吧
第一个代码好,第二个太笨重了。
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int maxn=200;
int c;
int m;
int l;
vector<pair<int,bool> >node;
int cmp2(pair<int,bool> q,pair<int,bool> q2)
{ return q.first>q2.first;
//以从小到大的顺序排列
}
bool dfs(int t,int len,int pos)
{ if(t==c+1) return true;
if(len==l) return dfs(t+1,0,0);
for(int i=pos;i<m;i++)
{ if(!node[i].second&&node[i].first+len<=l)//可以等于哦
{ //满足条件,可以放入了;
node[i].second=true;
if(dfs(t,len+node[i].first,i+1))
return true;
node[i].second=false;
if(len==0) return false;
while(i+1<m&&node[i].first==node[i+1].first)
i++;
}
}
return false;
}
int main()
{
int a;
while(~scanf("%d",&m))
{ node.clear();
if(m==0) break;
int sum=0;
for(int i=0;i<m;i++)
{ scanf("%d",&a);
sum+=a;
node.push_back(make_pair(a,false));
}
sort(node.begin(),node.end(),cmp2);
for(l=node[0].first;l<=sum;l++)
{ if(sum%l!=0) continue;
c=sum/l;
if(dfs(1,0,0))
{ printf("%d\n",l);
break;
}
}
}
return 0;
}
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#define eps 1e-6
#define LL long long
using namespace std;
const int maxn = 70;
const int INF = 0x3f3f3f3f;
int n, sumv, target, aim;//target表示目标的棍子个数,aim表示目标的棍子长度
int stick[maxn], vis[maxn];
bool cmp(int a, int b) {
return a > b;
}
void init() {
sumv = 0;
for(int i = 0; i < n; i++) {
cin >> stick[i]; sumv += stick[i];
}
sort(stick, stick+n, cmp);
}
bool dfs(int cnt, int len, int pos) {
if(cnt == target) return true;
if(len == aim) return dfs(cnt+1, 0, 0);
for(int i = pos; i < n; i++) { //从大到小排序后,按顺序搜索
if(!vis[i] && len+stick[i] <= aim) {
vis[i] = 1;
if(dfs(cnt, len+stick[i], i+1)) return true;
vis[i] = 0;
if(len == 0) return false; //如果第一根时失败剪枝
while(i+1 < n && stick[i+1] == stick[i]) i++; //如果下一根长度跟当前的失败的长度一样,剪枝
}
}
return false;
}
void solve() {
int ans = 0;
for(int i = 1; i <= sumv; i++) if(sumv % i == 0) {
memset(vis, 0, sizeof(vis));
aim = i; target = sumv / aim;
if(dfs(0, 0, 0)) {
ans = aim; break;
}
}
cout << ans << endl;
}
int main() {
// freopen("input.txt", "r", stdin);
while(scanf("%d", &n) == 1 && n) {
init();
solve();
}
return 0;
}