标签:style blog io ar for sp div c on
题意:有一些 木棍,它们的长度相同。现在将木棍折断,最多折成64根。
编程求木棍可能的最小长度。
越长的木棍对后面木棍的约束力越大,因此要把小木棍排序,按木棍长度从大到小搜索,这样就能在尽可能靠近根的地方剪枝。(剪枝一)
如果当前木棍能恰好填满一根原始木棍(可能已经是第二层甚至第N层DFS了,此时原始木棍长度要小于最外层原始木棍长度),但因剩余的木棍无法组合出合法解而返回,那么后面的遍历方针是是用更短的木棍组合来代替这根木棍,他们的总长恰好是当前木棍的长度(直接用长的都无法最终成功,用了小的更不可能成功,因为小的、零碎的用途更多),但因为当前木棍的做的事和这些替代木棍之和做的事一样,直接退出当前的枚举。(剪枝二)
显然最后一根木棍是不必搜索的
考虑每根原始木棍的第一根木棍,如果当前枚举的木棍长度无法得出合法解,就不必考虑下一根木棍了,当前木棍一定是作为某根原始木棍的第一根木棍的,现在不行,以后也不可能得出合法解。也就是说每根原始木棍的第一根小木棍一定要成功,否则就返回。(剪枝四)
剩下一个通用的剪枝就是跳过重复长度的木棍(剪枝五)
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int used[100],len[100],sum,n,Min,s[100];
int find(int p,int rest,int trest)
{
int i;
if (trest==Min) return 1;
//剩余所有的小木棍之和恰好是需要凑成的MIN
for (i=p;i<=n;i++)
if (!used[i]&&len[i]<=rest)
//这里必须要遍历,考虑某个组合木棍还缺少4,如果剩余的仅仅有3 2 2,
//如果把3加上则永远得不到成功的,因为必须要用2+2.
{
used[i]=1;
if (len[i]==rest)
{
if (find(1,Min,trest-len[i])) return 1;
//本次组合成功,查看其余小木棍能否成功因此//从1开始return不仅仅跳出循环,还跳出整个函数
} else if (find(i+1,rest-len[i],trest-len[i])) return 1;
//本次组合未完成,从更小的(i+1)开始搜索其余部分,使得和为rest
used[i]=0;//不成功如果成功不会进行到这里,因为前面已经RETURN跳出整个函数
if (len[i]==rest) return 0;
//剪纸2,跳出循环,不用再遍历了,这里的遍历即是用别的组合来得到rest
if (rest==Min) return 0; //剪纸4,跳出循环,不用再遍历了
while (len[i+1]==len[i]) i++;//(剪枝五)
}
return 0;
}
bool cmp(int a,int b) {return a>b;}
int main()
{
int i;
while (scanf("%d",&n)&&n!=0)
{
for (i=1;i<=n;i++)
scanf("%d",&len[i]);
memset(used,0,sizeof(used));
sort(len+1,len+n+1,cmp);
sum=0;
for (i=1;i<=n;i++) sum+=len[i];
Min=len[1];
while (sum%Min!=0) Min++;
s[n+1]=0;
while (find(1,Min,sum)==0)
{
Min++;
while (sum%Min!=0) Min++;
}
printf("%d\n",Min);
}
return 0;
标签:style blog io ar for sp div c on
原文地址:http://www.cnblogs.com/notlate/p/4010858.html