试题 算法训练224 Sticks

资源限制

时间限制:1.0s 内存限制:999.4MB
  Sticks
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 113547 Accepted: 26078

问题描述

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.

输入格式

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.

输出格式

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

样例输入

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

样例输出

5
6

dfs+剪枝算法
1)要确定好target,也就是um of sticks的约数且要大于最大的木棍
2)木棍排序,从大到小排
3)在满足一个target的任务中,因为顺序排列,所以重复元素,前面没选的,这一次也不选,剪枝
4)在满足一个target的任务中,如果当前最长的木棍满足失败,则整条枝失败,因为我们从小到大排列,会越来越小

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<set>
#include<sstream>
#include<string>
#include<vector>

using namespace std;

bool vis[65]; // 是否选过
int tm[65]; //储存小木棍长度
int target; //目标长木棍长度
int flag; //完成指示
int n; //输入个数
/*共64个格子一行,填格子。
deep代表第几个格子
len 代表当前目标长度
num 代表当前小棒序号*/
void dfs(int deep, int len, int num) 
{
    
    
	int i;
	if (flag) return;//指示完成,直接返回。
	if (len == 0) 
	{
    
    
		//len == 0说明前面都已经完成,开始新的一轮
		i = 1;
		while (vis[i])
			i++;
		vis[i] = true;
		dfs(deep + 1, len + tm[i], i + 1);
		vis[i] = false;//目前最长棍都失败,不用继续,直接退出,失败。
		return;
	}
	if (len == target)
	{
    
    
		if (deep == n) //格子填完,表示所有木棍被选,成功
			flag = 1;
		else
			dfs(deep, 0, 0);//还未填完,开始新的一轮
		return;
	}

	//不是新开始,也不是刚好结束,那就是要找棍子
	for (i = num; i <= n; i++)
	{
    
    
		if (!vis[i] && len + tm[i] <= target) //可以选并且还不满足target
		{
    
    
			if (!vis[i - 1] && tm[i] == tm[i - 1]) //上一根一样长且没被选过,那这一根也没必要
				continue;
			vis[i] = true;
			dfs(deep + 1, len + tm[i], i + 1); //下一个格子
			vis[i] = false;//失败,放下棍子
			if (tm[i] + len == target) return; //满足了,但是前面验证过失败了,所以之后都不用尝试了
			if (flag) return;
		}
	}
	if (flag) return;
}

bool cmp(int a, int b)
{
    
    
	return a > b;
}
int main()
{
    
    
	while (cin >> n && n)
	{
    
    

		int sum = 0;
		int i;
		for (i = 1; i <= n; i++) // 注意从1开始
		{
    
    
			scanf("%d", &tm[i]);
			sum += tm[i];
		}
		sort(tm + 1, tm + 1 + n, cmp); //自定义cmp,大于返回为1,按照从大到小排列

		for (i = tm[1]; i <= sum; i++)
		{
    
    
			if (sum%i) continue;
			flag = 0;
			memset(vis, 0, sizeof(vis)); //全部取0,表示未被选择
			target = i;
			dfs(0, 0, 1); //第0个格子,目前长度为0,当前目标小棒序号为1
			if (flag)
			{
    
    
				printf("%d\n", i); break;
			}
		}

	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39117858/article/details/104299039