标签: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