Sticks

链接:http://acm.hust.edu.cn/vjudge/problem/14913/origin

题目: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.

题意:有一堆长度不同的木棍,用他们去拼成一些长度相等的木棍,问,长度相等的木棍最短为多少。

分析:这是一道稍显复杂的搜索题,答题思路是从0开始枚举长度,挨个去寻找看是否成功,需要找到一些规则来优化,否则会超时。第一个优化:枚举范围,最短的长度一定大于等于单个最长的小木棍,而且保证能被总长度除尽,最长为总长度(可以简化成总长度的一半,一旦超过了,就只能是总长度了),第二个优化:把小木棍从大的开始选择,这样对于目标长度,比如3,会优先选择木棍少的情况,比如3,12,111的情况要优先选择3,因为木棍越短,数量越多拼凑起来越灵活,对复杂的情况有帮助。第三个优化,同一个长度的木条,在同一个阶段,只尝试一次(非常的重要),比如在选择第二条木棒3+2(第一个2)+。。。失败了,就不要再尝试3+2(第二个,第三个。。)了,因为不会成功的。题目不是很难,不过剪枝的比较多,比较考验细心程度。wrong出翔。

题解:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <string>
#include <cstring>
#include <functional>
#include <cmath>
#include <cctype>
#include <cfloat>
#include <climits>
#include <complex>
#include <deque>
#include <list>
#include <set>
#include <utility>
#define rt return
#define fr freopen("in.txt","r",stdin)
#define fw freopen("out.txt","w",stdout)
#define ll long long
#define ull unsigned long long
#define detie ios_base::sync_with_stdio(false);cin.tie(false);cout.tie(false)
#define pii pair<int,int>
#define lowbit(x) x&(-x)
using namespace std;
#define maxi 0x3f3f3f3f
#define MAX 300020

int s[MAX];
bool v[MAX];
int sum;
int n;

bool dfs(int pos, int res, int len) {
	if (pos == 0 && res == 0)
		rt true;
	if (res == 0)
		res = len;
	for (int i = n - 1; i >= 0; i--){
		if (v[i] || s[i] > res)
			continue;
		v[i] = true;
		if (dfs(pos - 1, res - s[i], len))
			rt true;
		v[i] = false;
		if (res == s[i] || res == len)//重要的剪枝,长度相同不会重复尝试。
			rt false;
	}
	rt false;
}

int main(){
	//fr;
	detie;
	while (cin >> n&&n){
		sum = 0;
		for (int i = 0; i < n; i++){
			cin >> s[i];
			sum += s[i];
		}
		sort(s, s + n);
		int i;
		for (i = s[n - 1]; i <= sum/2;i++){
			if (sum%i)
				continue;
			memset(v, 0, sizeof v);
			if (dfs(n,i,i)){
				printf("%d\n", i);
				break;
			}
		}
		if (i > sum / 2)
			printf("%d\n", sum);
	}
	rt 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值