Description
George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.
The input file contains blocks of 2 lines. The first line contains the number of sticks parts after cutting. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.
The output file contains the smallest possible length of original sticks, one per line.
9 5 2 1 5 2 1 5 2 1 4 1 2 3 4 0
6 5
把数据按降序排列,从最大的开始判断,一直判断到所有数据和的一半,如果都拼不成功,那么只能拼成一根喽!
四次剪枝:
1、不要在同一位置尝试同一根木棒,即如果某根木棒拼不成功,那么跟它相同的木棒都不用继续判断直接跳过。
假如 5 5 4 4 3 要拼长度为6的木棍是 用5拼不可能成功,那个第二个长度为5的木棒就不用判断了。
2、如果由于以后的拼接失败,需要重新调整第i根棍子的拼法,则不会考虑替换第i根棍子中的第一根木棒(换了也没用)。why?
因为假设替换后能全部拼成功,那么这被换下来的第一根木棒,必然会出现在以后拼好的某根棍子k中。
3、不要希望通过仅仅替换已拼好棍子的最后一根木棒就能够改变失败的局面。
因为把已拼好棍子的最后一根木棒替换下来,那么肯定有一个或者两个或者更多拼在一起是最后一根木棒的长度,把它放在后面就好了! 干嘛要替换人家最后一根木棒呢。
4、每次找一根木棒的时候,只要这不是一根棍子的第一条木棒,就不应该从下标为0的木棒开始找,而应该从刚刚(最近)接上去的那条木棒的下一条开始找。
因为按降序排列的么,上面的都不行,肯定只判断下面的喽!
代码如下
#include<iostream> #include<cstdio> #include<map> #include<math.h> #include<cstring> #include<algorithm> using namespace std; int tused[100], tlength[100], s, m, n; bool cmp(int A, int B) { return A > B; } int Dfs(int M, int L, int pos) { if(M == 0 && L ==0) { return 1; } if(L == 0) { pos = -1;//剪枝4 L = m;//如果刚好拼好,接着拼下一根 } for(int i = pos + 1; i < n; i++) { if(!tused[i] && tlength[i] <= L) { if(i > 0) { if((tlength[i - 1] == tlength[i]) && (!tused[i-1])) continue;//剪枝1 } tused[i] = 1;//标记已使用 if(Dfs(M - 1, L - tlength[i], i)) return 1; else { tused[i] = 0; if(tlength[i] == L || L == m) return 0;//剪枝 2 3 } } } return 0; } int main() { int i, sum; while(scanf("%d",&n) && n) { sum = 0; for(i = 0; i < n; i++) { scanf("%d",&tlength[i]); sum += tlength[i]; } sort(tlength, tlength + n, cmp);//按降序排列 for(m = tlength[0]; m <= sum / 2; m++) { if(sum % m != 0) continue;// 不加这个条件超时鸟~~~~加上100ms以下! memset(tused, 0, sizeof(tused)); if(Dfs(n ,m, -1))//n代表木棒的个数,m为长度,-1位要访问的木棒序号 { printf("%d\n",m); break; } } if(m > sum / 2) printf("%d\n",sum); } return 0; }