POJ1011-Sticks 搜索

19 篇文章 0 订阅
4 篇文章 0 订阅

Sticks
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 151709 Accepted: 36124

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.

Input

The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.

Output

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

链接

一、题意

        现在有n根长度不一的小木棒,要求将其拼凑成长度相等的木棒若干。要求输出长度最短的可能。

二、思路

        主要思路是搜索,但要加上剪枝才能不超时。搜索时传入剩余的木棒数量,当前已经拼凑的长度。按照我的搜索策略,主要有一下几种剪枝:

                1.设拼凑完成后长度为len,则len必定能整除原来木棒的长度和sum。

                2.对于新的一次拼凑过程,即当前已经拼凑的长度为0,则要求此次拼凑必须成功。因为若此次拼凑不能成功,意味着存在一根木棒,在以后的搜索过程中都不会完成拼凑。

                3.对源木棒进行降序排列,先拼凑长木棒。

                4.搜索过程中,对于长度相等的木棒应该避免重复搜索。

        即使这样,Discuss中的数据还是要7秒左右。

三、代码

#include <iostream>
#include <sstream>
#include <iomanip>
#include <string>
#include <numeric>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <utility>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>

using namespace std;
typedef long long ll;
const int MAXN = 1000;
const int MOD7 = 1000000007;
const int MOD9 = 1000000009;
const int INF = 2000000000;//0x7fffffff
const double EPS = 1e-9;
const double PI = 3.14159265358979;
const int dir_4r[] = { -1, 1, 0, 0 };
const int dir_4c[] = { 0, 0, -1, 1 };
const int dir_8r[] = { -1, -1, -1, 0, 0, 1, 1, 1 };
const int dir_8c[] = { -1, 0, 1, -1, 1, -1, 0, 1 };

int n;
int val[MAXN];
bool visited[MAXN];

bool myCom(int a, int b) {
	return a > b;
}

bool dfs(int left, int cur, int len, int beg) {
	if (left == 0 && cur == 0)
		return true;
	else if (cur == 0) {
		//如果是拼接一根新的木棒,则这根木棒必须完成拼接
		int index = 0;
		while (visited[index])
			index++;
		visited[index] = true;
		if (dfs(left - 1, val[index] % len, len, index + 1))
			return true;
		visited[index] = false;
		return false;
	}

	for (int i = beg; i < n; ++i)
		if (!visited[i])
			if (cur + val[i] <= len) {
				visited[i] = true;
				if (dfs(left - 1, (cur + val[i]) % len, len, i + 1))
					return true;
				visited[i] = false;
				//减少重复搜索
				while (i < n && val[i + 1] == val[i])
					i++;
			}

	return false;
}

int main() {
	while (scanf("%d", &n) && n) {
		int sum = 0;
		for (int i = 0; i < n; ++i) {
			scanf("%d", val + i);
			sum += val[i];
		}
		sort(val, val + n, myCom);

		int len;
		for (len = val[0]; len < sum; ++len)
			if (sum % len == 0) {
				memset(visited, false, sizeof(visited));
				if (dfs(n, 0, len, 0))
					break;
			}
		printf("%d\n", len);
	}

	//system("pause");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值