poj_1011木棒

木棒
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 106153   Accepted: 24209

Description

乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。

Input

输入包含多组数据,每组数据包括两行。第一行是一个不超过64的整数,表示砍断之后共有多少节木棍。第二行是截断以后,所得到的各节木棍的长度。在最后一组数据之后,是一个零。

Output

为每组数据,分别输出原始木棒的可能最小长度,每组数据占一行。

Sample Input

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

Sample Output

6
5
参考:http://www.cppblog.com/y346491470/articles/155318.html
【题解】:不得不说,这道题出得非常好,特别是uva那里的大数据(poj的数据太水了),对于剪枝能力要求很高。下面说下几个重要的剪枝:
1.把所有木棍的长度从大到小排列,组合木棒时优先使用长的木棍,这样可以加快组合速度,并且对后面的剪枝有帮助。
2.木棒的长度一定是大于等于最长木棍的长度并且小于等于所有木棍长度的和,这个很容易证明。
3.木棒的长度一定是所有木棍长度的和的约数,这个也很容易证明。
4.在某一个木棒的组合过程中,对于当前的木棍stick[i],如果stick[i-1]没有被组合并且stick[i] == stick[i-1],那么不用考虑stick[i],显然stick[i]最终也不会被组合。
5.如果此次是在尝试第i个木棒的第一段,假设stick[j]为当前可以被使用的最长的木棍,如果此次组合失败,直接退出搜索,即退回到对第i-1个木棒的搜索。试想:失败说明现在使用stick[j]是不可行的,那么以后无论什么时候使用stick[j]都是不可行的,因为以后再处理stick[j]时可使用的木棍一定是当前可使用的木棍的子集,在更多木棍选择的情况下都不能组合成功,那么,在更少木棍选择的情况下一定不能组合成功。
#include <cstring>
#include <iostream>
#include <cstdio>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
#define MAX 65
#pragma warning( disable : 4996) 
int n, sum, goal;
int stick[MAX];
bool vis[MAX];

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

bool dfs(int now, int index, int cnt)
{
	if(goal * cnt == sum)
	{
		return true;
	}
	for(int i = index; i < n; i++)
	{
		if(vis[i] || (i && !vis[i-1] && stick[i] == stick[i-1]))
		{
			continue;
		}
		if(now + stick[i] == goal)
		{
			vis[i] = true;
			if(dfs(0, 0, cnt + 1))
			{
				return true;
			}
			vis[i] = false;
			return false;
		}
		else if(now + stick[i] < goal)
		{
			vis[i] = true;
			if(dfs(now + stick[i], i + 1, cnt))
			{
				return true;
			}
			vis[i] =false;
			if(now == 0)
			{
				return false;
			}
		}
	}
	return false;
}

int main()
{
	freopen("in.txt", "r", stdin);
	while (scanf("%d", &n)!= EOF)
	{
		if(n == 0) break;
		sum = 0;
		for(int i = 0; i < n; i++)
		{
			scanf("%d", &stick[i]);
			sum += stick[i];
		}
		sort(stick, stick + n,cmp);
		for(goal = stick[0]; goal < sum; goal++)
		{
			if(sum % goal != 0)
			{
				continue;
			}
			memset(vis, false, sizeof(vis));
			if(dfs(0, 0, 0)) break;
		}
		printf("%d\n",goal);
	}
}


posted @ 2013-04-13 09:50  N3verL4nd  阅读(128)  评论(0)    收藏  举报