很经典的dfs剪枝,被困了一个晚上,第二天成功出逃,贴代码纪念下
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<list>
#include<vector>
#include<stdlib.h>
#include<algorithm>
using namespace std;
#define MAX 66
int a[MAX];
int sum; //总长度
int max_; //最大的一段
int every; //每次循环保存一段的长度
int result; //最后结果
int book[MAX];
int n;
void dfs(int temp,int k,int time){
if(temp==every){ //当前一枝已满足长度
if(k+2==(sum/every)){ //若满足的数量为总数量减一
result = every; //该数满足结果
return ;
}
else{
dfs(0,k+1,0); //进入下一枝的循环
}
}
else{
for(int i=time;i<n;i++){
if(!book[i]){ //没被计入
if((temp+a[i]>every)){ //递减序列,若a[i]过大,略过
continue ;
}
else if((i>0&&a[i]==a[i-1]&&!book[i-1])){ //若当前数字与之前数字相同且前一数字没被计入,则同类数字都被略去
continue;
}
else{
book[i] = 1;
dfs(temp+a[i],k,i+1);
book[i] = 0;
if(temp==0){ //若每个枝第一个数字都不满足,则该循环无效,不用继续循环,返回上一层
return ;
}
}
if(result!=sum){ //有结果,退出
return ;
}
}
}
}
}
int main()
{
scanf("%d",&n);
while(n){
max_ = 0;
sum = 0;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
sum += a[i];
if(max_<a[i]) max_ = a[i];
}
if(sum/max_<=1){ //剪枝 1:max超过半数以上
printf("%d\n",sum);
}
else if(max_*2==sum){ //恰好为半数
printf("%d\n",max_);
}
else{
result = sum;
sort(a,a+n,greater<int>()); //从大到小
for(int i=max_;i<sum/2+1;i++){ //从最大数开始 到总和的一半以上结束
if(sum%i==0){ //整除
memset(book,0,sizeof(book));
every = i; //每一份的长度
dfs(0,0,0);
if(result!=sum){ //得到一值即为结果
break;
}
}
}
printf("%d\n",result);
}
scanf("%d",&n);
}
return 0;
}
输入:
9 5 2 1 5 2 1 5 2 1 4 1 2 3 4 0输出:
6 5输入:
12
1 1 2 2 2 3 3 3 3 3 3 4
27
15 3 2 4 11 1 8 8 8 15 3 2 4 11 1 8 8 8 15 3 2 4 11 1 8 8 8
9
15 4 3 1 2 8 11 8 8
45
15 3 2 11 4 1 8 8 8 15 3 2 11 4 1 8 8 8 15 3 2 11 4 1 8 8 8 15 3 2 11 4 1 8 8 8 15 3 2 11 4 1 8 8 8
0
输出:
6 20 20 20