一个DFS的经典题目,在搜索的过程中,还要不断的进行剪枝的过程,避免不必要的搜索时间的浪费
1.测试的最小棒长度必须是所有棒长的因数。//sum%currentlength==0;
2.降序排列后,取第一个(也就是最长的一个进行尝试搜索),如果第一个木棒参与的搜索也失败,就停止。举例子说:比如拿个贪心的sample,比如我拿15凑30,假设不成功,就不必把15替换成11继续搜索。因为如果30是最小长度,则15必须能与其他木棒成功匹配。
3.比如现在我要凑30,我已经有了25,而且我正好找到了5长度的棒子。但是最终失败。至此,这个搜索就可以停止了。因为如果5后面还有比5小的长度,比如1 1 1 1 1,也正好能组成5,但是整数5的灵活性比不上5个1强,整数留到后面给其他棒子匹配也必然失败。(有点贪心的味道)
4.重复的就不用搜索了。
#include "stdio.h"
#include "string.h"
#define MAX 65
int sticks[MAX] , len , n;
int used[MAX];
void sort(int a[] , int begin , int end)
{
int i , j , tmp ;
for( i = begin+1 ; i <= end ; i++ )
{
tmp = a[i];
for( j = i ; j > begin && a[j-1] < tmp ; j-- )
a[j] = a[j-1];
a[j] = tmp;
}
}
int dfs(int i , int l , int t) // t是棍子长度的总和 l为要拼成时还需要的长度
{
int j;
if(l == 0)
{
t -= len;
if( t == 0)
return 1;
for( i = 0 ; used[i] ; i++ ) //找到第一个还未使用的棒子
;
used[i] = 1;
if(dfs(i+1,len-sticks[i],t))
return 1;
used[i] = 0; //如果不适合就将棍子放回去
t += len; //总长度还是置为原来的总长度
}
else
{
for( j = i ; j <= n ; j++ )
{
if( j > 0 && (sticks[j] == sticks[j-1] && !used[j-1]))
continue;
if(!used[j]&&l>=sticks[j])
{
l -= sticks[j];
used[j] = 1;
if(dfs(j,l,t))
return 1;
l += sticks[j];
used[j] = 0;
if(sticks[j]==l)
break;
}
}
}
return 0;
}
int main()
{
int i , sum , flag;
while(scanf("%d",&n) && n)
{
sum = 0;
flag = 0;
for( i = 0 ; i < n ; i++ )
{
scanf("%d",&sticks[i]);
sum += sticks[i];
used[i] = 0;
}
sort(sticks,0,n-1);
for(len = sticks[0]; len <= sum/2; ++len)
{
if(sum%len == 0)
{
if(dfs(0,len,sum))
{
flag = 1;
printf("%d\n",len);
break;
}
}
}
if(!flag)
printf("%d\n",sum);
}
return 0;
}