//代码比较长,好在逻辑比较清晰吧
//调bug调了挺久,错在 我直接返回false,未回撤对visit的修改。因为在当前情况下不可行,不代表其他深搜路劲不行
#include <cstdio>
#include <algorithm>
#include <cstring>
using std::sort;
using std::memset;
int n;
const int MAX = 70;
int stick[MAX];
bool visit[MAX];
bool cmp(int a,int b)
{
return a>b;
}
bool match(int singlelength, int remain, int startindex, int matchnum)
{
if(matchnum == n)
return true;
if(remain == singlelength)//剪枝2:重拼一个木棍的时候,只需要看第一个要匹配的能不能成功
{
while(visit[startindex] && startindex< n) startindex++;
if(remain == stick[startindex])
{
visit[startindex] = true;
if( match(singlelength, singlelength, 0, matchnum+1))
return true;
visit[startindex] = false;
}
else
{
visit[startindex] = true;
if(match(singlelength, remain-stick[startindex], startindex, matchnum+1))
return true;
visit[startindex] = false;
}
}
else
{
int same1 = -1;//剪枝3:相同的木棍,如果不行,不需要重试。
for(int i = startindex ; i < n; i++)
{
if(visit[i] || same1 == stick[i])
continue;
if(remain < stick[i])
continue;
if(remain == stick[i])
{
visit[i] = true;
if(match(singlelength, singlelength, 0, matchnum +1))
return true;
else
same1 = stick[i];
visit[i] = false;
}
else{
visit[i] = true;
if(match(singlelength, remain-stick[i], i, matchnum+1))
return true;
else
same1 = stick[i];
visit[i] = false;
}
}
}
return false;
}
int main()
{
while(scanf("%d",&n)&&n)
{
int maxlength = 0;
int sumlength = 0;
memset(visit, 0, sizeof(visit));
for(int i= 0 ; i < n; i++)
{
scanf("%d",&stick[i]);
if(maxlength < stick[i])
maxlength = stick[i];
sumlength += stick[i];
}
sort(stick, stick+n, cmp);
bool flag = false;
//剪枝1:只有sumlength的约数才有可能成为dividelength,这里dividelength表示拼成的木棍长
for(int dividelength = maxlength; dividelength <= sumlength; dividelength ++)
{
if(sumlength % dividelength)
continue;
memset(visit, 0, sizeof(visit));
if(match(dividelength, dividelength, 0, 0))
{
printf("%d\n",dividelength);
flag = true;
break;
}
}
}
return 0;
}
转载于:https://www.cnblogs.com/wead-hsu/p/3712292.html