POJ 1011 (13.07.23)

 Sticks 

George took sticks of the same length and cut them randomly until all partsbecame at most 50 unitslong. Now he wants to return sticks to the original state, but he forgothow many sticks he had originally andhow long they were originally. Please help him and design a program whichcomputes the smallest possibleoriginal length of those sticks. All lengths expressed in units are integersgreater than zero.

Input

The input file contains blocks of 2 lines. The first line contains thenumber of sticks parts after cutting.The second line contains the lengths of those parts separated by thespace. The last line of the file contains zero.

Output

The output file contains the smallest possible length of original sticks,one per line.

Sample Input

9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0

Sample Output

6
5

题意:
找出一个最短长度, 使得N个棒子以任意数目组合, 正好用完这些棒子, 每一组长度都是这个最短长度
例如 第一个样例 5+1 5+1 5+1 2+2+2 都是等于6 所以答案是6 搞清楚题意就想做法: 这题有很多需要剪枝的地方(代码中有标识) 另外需要先对小木棍排序, 从大到小 因为假如是1 2 3 4这样的数据, 那么组成全部长度都为1的木棍是没有可能的, 应该最小从4开始组合 另外如果1 2 3 4的总长度是10, 那么如果组成长度为5的木棍失败, 那么去组6是不可能了, 因为剩下的长度是4, 这是矛盾 所以搜索区间应该是[小棍中最长的一根长度, 总长度的一半] 我的代码只在POJ上通过, 在UVA上没过...Runtime error... 大家可以帮我找找哪里还可以剪枝 POJ AC代码 
#include<stdio.h>
#include<algorithm>
#include<stdlib.h>

using namespace std;

int n;

int cmp(int a, int b) {
	return a > b;
}

int DFS(int *stack, int curlen, int aimlen, int sta, int *vis, int num) {
	if(num == n)
		return 1;

	int same = -1;
	for(int i = sta; i < n; i++) {
		if(vis[i] || stack[i] == same) //剪二:判断是否用过此小枝, 且相同长度的小枝不重复用
			continue;

		vis[i] = 1;
		if(curlen + stack[i] < aimlen) {
			if(DFS(stack, curlen + stack[i], aimlen, i, vis, num+1))
				return 1;
			else
				same = stack[i];
		}

		else if(curlen + stack[i] == aimlen) {
			if(DFS(stack, 0, aimlen, 0, vis, num+1))
				return 1;
			else
				same = stack[i];
		}
		vis[i] = 0;

		if(curlen == 0) //剪三:如果第一个棒子都没的组, 长度还是0, 那么不用再找, 已经行不通了
			break;
	}
	return 0;
}

int main() {
	while(scanf("%d", &n) && n) {
		int sumlen = 0;
		int *stack = new int[n];
		int *vis = new int[n];

		for(int i = 0; i < n; i++) {
			scanf("%d", &stack[i]);
			sumlen += stack[i];
			vis[i] = 0;
		}

		int flag = 1;
		sort(stack, stack + n, cmp);
		int maxlen = stack[0];
		for(int aim = maxlen; aim <= sumlen - aim; aim++) {
			if(sumlen % aim == 0 && DFS(stack, 0, aim, 0, vis, 0)) { //剪一:这么多棒子的总长度, 对所求的长度取余必须为0;
 				printf("%d\n", aim);
				flag = 0;
				break;
			}
		}
		if(flag)
			printf("%d\n", sumlen);
		delete stack;
		delete vis;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值