POJ 1011 Sticks(搜索+剪枝)

版权声明:From: http://blog.csdn.net/tju_tahara https://blog.csdn.net/TJU_Tahara/article/details/52177278
Sticks
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 138243   Accepted: 32574

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.

Sample Input

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

Sample Output

6
5

Source

Central Europe 1995



题意:

本来有好多个长度相等的木条,把它们切开。最后分为好多根,问你还原木条之后最短是多长。

思路:

这是一道很经典的搜素+剪枝。本来以为自己已经会搜索了,做这道题还是一脸懵逼。各种wa各种tle。还是自己太年轻。

要注意的点:

1、不可以用贪心求解,即使是DFS+贪心也不行。附上大神的数据,可以卡掉贪心的解法:

	27
	15 3 2 4 11 1 8 8 8 15 3 2 4 11 1 8 8 8 15 3 2 4 11 1 8 8 8   ANS:20
2、要进行多次剪枝。第一次是取到的长度必须是总长度的因子。第二次剪枝是每一次取出一组长度为len的木条时必须从没有被取出的第一个开始取。(可以想一想,这一次没有从第一个开始取,那以后这个树枝就再也取不到了,所以这种情况必定是一种false的情况。第三个剪枝是如果长度为lenx的木条被取过后不行,那么跳过后面所有长度为lenx的木条(这个剪枝挺重要的,如果出现很多木条长度相等的情况,就可以看出时间的差别了。附上另外某大神找出的一组数据,可以看出第三个剪枝带来的效果)

64
40 40 30 35 35 26 15 40 40 40 40 40 40 40 40 40 40 40 40 40 40 

40 40 43 42 42 41 10 4 40 40 40 40 40 40 40 40 40 40 40 40 40 

40 25 39 46 40 10 4 40 40 37 18 17 16 15 40 40 40 40 40 40 40 40
ANS :454		(两组数据都可以在poj的discuss上看到)

3、记得给木条排序,从大到小排序一遍。因为一开始排序了,所以我不知道没有排序对运行时间有多大影响。

POJ的数据还是比较水的。就比如如果上面那一组数据有的代码根本跑不出来,或者7min+, 我的代码也需要大概1s才能出结果。不过评测机还是AC了。


AC代码(Memory: 164K Time: 16MS)


#include <iostream>
#include <cstring>
#include <cstdio>
#include <map>
#include <algorithm>
using namespace std;

int arr[100];
bool oc[110];
inline bool cmp(const int& a, const int& b){
	return a > b;
}

bool dfs(int s, const int& num, int sum, const int& sumn, int cent, const int& tot){
	int k = 0;
	if(cent == tot) return true;
	if(sum == 0) {
		for(k = 0; oc[k]; k++);
		return dfs(k, num, sumn, sumn, cent + 1, tot);
	}
	int i;
	if(sumn == sum){
		for(; oc[s]; s++);
		oc[s] = 1;
		if(!dfs(s + 1, num, sum - arr[s], sumn, cent, tot)){
			oc[s] = 0;
			return false;
		}
		return true;
	}
	for(i = s; i < num; i++){
			if(oc[i]) continue;
			if(sum >= arr[i]){
				oc[i] = 1;
				if(dfs(i + 1, num, sum - arr[i], sumn, cent, tot)) return true;
				else{
					oc[i] = 0;
					while(arr[i] == arr[i + 1]) i++;
				}
			}
	}
	return false;
}

int main()
{
	int num, i, sum, k, countn;
	while(~scanf("%d", &num) && num){
		sum = 0;
		for(i = 0; i < num; i++){
			scanf("%d", &arr[i]);
			sum += arr[i];
		}
		sort(arr, arr+num, cmp);
		for(k = arr[0]; k < sum; k++){
			if(sum % k != 0) continue;
			countn = sum / k;
			memset(oc, 0, sizeof(oc));
			if(dfs(0, num, k, k, 0, countn)) break;
		}
		printf("%d\n", k);
	}
	return 0;
}



猜你喜欢

转载自blog.csdn.net/TJU_Tahara/article/details/52177278