这道题我还是用回溯法+剪枝
不过这道题必须要减的比较深才能通过。
剪纸分析:
1.总长度必须要比数据的任一都要长,
2.如果木棍要多于一个,那么该长度必须不是素数。
3.每个木棍的长度是总长度的约数。
#include <stdio.h>
#include<stdlib.h>
#include <string.h>
int st[65];
int mark[65];
int s, j, n;
int cmp(const void *a,const void *b)
{
return *(int *)a-*(int *)b;
}
int dfs(int sum, int k, int cnt){ //sum 是正在拼的木棍已经拼出的长度, k是从哪根碎木块开始拼,cnt是正在拼第几根木棍
if (cnt == s) //如果拼的木块数等于总长度除以所枚举的木棍长度
return 1;
else if (sum == j)//如果本根木块拼完,拼下一根,再次从第0根木棍开始找
return dfs(0, 0, cnt + 1);
else
{
int pre, i;
for (pre = 0, i = k; i < n; i++)//枚举木棍
if (mark[i] && st[i] + sum <= j) //如果这根木棍被加过,并且它不等于前一块的长度
{
mark[i] = 0;
if (dfs(sum + st[i], i + 1, cnt))//从下一根木棍开始搜索
break;
mark[i] = 1; //如果向下搜索不成功回溯
if (k == 0)
return 0;//如果回溯后k==0说明这根正在被还原的这根木棍还原失败了.也就是说剩下的木棍不足以拼出原始木棍
}
if (i == n) //如果i < n 说明 搜索到成果了,若搜到 i == n-1 还未搜索到说明失败, 需要回退了
return 0;
else
return 1;
}
}
int main()
{
int i, sum;
while(scanf("%d",&n), n)
{
for (i = sum = 0; i < n; i++)
{
scanf("%d",&st[i]);
sum += st[i];
}
qsort(st,n, sizeof(st),cmp);//以降序序列排序,首相值为木块最大值
for (j = st[0]; j < sum; j++) //最长的木棍的长度一定不会超过以前的木棍长度,所以从最长的长度开始枚举
if (sum % j == 0)
{
s = sum / j;
memset(mark, 1, sizeof(mark));
if (dfs(0, 0, 0)) break;
}
if (j == sum)
printf("%d",sum);
else
printf("%d",j);
}
return 0;
}