这道题提交20多次才通过。主要原因是没有每次将flag标志重置为false。
思想:木棒长度肯定介于最大的木棒长度和木棒总长度之间,且是木棒总长度的约数(因素)。
第一步:对输入的从大到小排序,同时求出木棒总长度。
第二走:从最长木棒到木棒总长度之间一次循环,显然数组的一个根就是最长木棒。
第三步:深度搜索。记录当前拼凑木棒的长度,当前数组访问下表,当前深搜深度。
(1)如果当前拼凑木棒长度为0,那么取出没有访问过的最长木棒,继续深搜。
(2)如果当前拼凑木棒长度==需要拼凑出来的木棒长度,本次拼凑完成。如果深度为总木棒数,表示深搜完成,退出。
否则,继续深搜。
(3)如果当前拼凑木棒长度小于等于需要拼凑出来的木棒长度,则开始查找,查找未访问的,且待用长度与目前拼凑木棒长度小于等于拼凑出来的木棒长度。
需要剪枝,如果上一个拼凑不成功,且这一个和上一个长度一致,则这一个也和上次一样不会成功。
否则,继续深搜。
拼凑不成功,必须回溯,即将未拼凑成功的重置未访问标志。
深搜完成,可以提前退出。找到木棒长度,立即终止循环。
肯定会有答案出现,所有搜索不成功时,木棒总长度即为答案。
#include<iostream>
#include<algorithm>
#define SIZE 65
using namespace std;
int n;
int a[SIZE];
int visit[SIZE];
int len;
int flag = 0;
int compare(int a, int b){
if( a>b)
return 1;
return 0;
}
void dfs(int dep,int curlen,int pos ){
if(flag )
return ;
if(curlen == 0){
int k= 0;
while(visit[k])
k++;
visit[k] = 1;
dfs(dep + 1, a[k], k + 1);
//visit[k] = 0;
return ;
}
if(curlen == len){
if(dep == n) flag = 1;
else dfs(dep, 0, 0);
return ;
}
for(int i = pos; i < n; i ++)
if(!visit[i] && curlen + a[i] <= len)
{
if(!visit[i-1] && a[i] == a[i-1])
continue;
visit[i] = 1;
dfs(dep + 1, curlen + a[i], i + 1);
visit[i] = 0;
}
}
int main(void){
while(cin>>n && n>0){
int sum = 0;
flag = 0;
for(int i=0;i<n;i++){
cin>>a[i];
sum += a[i];
}
sort(a,a+n,compare);
for(len=a[0];len<sum;len++){
if(sum % len == 0){
memset(visit,0,sizeof(visit));
dfs(0, 0, 0);
if(flag) break;
}
}
cout<<len<<endl;
}
return 0;
}