奥赛一本通 小木棍

这篇博客介绍了一种动态规划的算法,用于解决乔治将小木棍随意砍断后,如何根据每段小木棍的长度,找出原始木棍的最小可能长度。题目来源于CERC1995,输入包含小木棍的数量和每段的长度,通过排序和回溯的方法找到最佳组合。输出为原始木棍的最小长度。
摘要由CSDN通过智能技术生成

题目描述

原题来自:CERC 1995

乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过 50 。现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。

输入格式

第一行为一个单独的整数 N 表示砍过以后的小木棍的总数。 第二行为 N 个用空格隔开的正整数,表示 N 根小木棍的长度。

输出格式

输出仅一行,表示要求的原始木棍的最小可能长度。

样例

输入数据 1

9
5 2 1 5 2 1 5 2 1

Copy

输出数据 1

6

Copy

数据范围与提示

1≤N≤60

#include<bits/stdc++.h>
using namespace std;
int n;
int a[70],vis[70];
int sum,res, ans;
bool cmp(int x,int y)
{
	return x > y;
}

int dfs(int len,int sta,int now)//(当前剩余的长度,搜索到第几根木棍,已经用了几次)
{
	int i,j;
	if(now == res)return 1;
	if(len == 0)//用完了进行下一次
		if(dfs(ans,1,now + 1))//每次都要从头开始搜索
			return 1;
	for(i = sta;i <= n;i ++)//挑选下一根木棍
	{
		if(!vis[i] && a[i] <= len)//该木棍之前还没有选过且长度合理
		{
			vis[i] = 1;//选上
			if(dfs(len - a[i],i + 1,now))//因为是从大到小挑选的,i + 1可以保证不会从小的挑到大的
				return 1;
			vis[i] = 0;//回溯
			if(ans == len)break;
			while(a[i] == a[i + 1])i ++;
			/*
				如果ans==len说明有比原长度更大的木棍出现,那就不可能塞得下了,所以可以剪枝
				去重剪枝 相同长度的不符合条件的则不需再搜索
			*/
		}
	}
	return 0;       
}

int main()
{
		cin >> n;
		int i,j;
		for(i = 1;i <= n;i ++)
		{
			cin >> a[i];
			sum += a[i];
		} 
		sort(a + 1,a + 1 + n,cmp);//先配大的,再配小的,因为小的作用更大
		for(j = a[1];j <= sum;j ++)
		{   
			if(sum % j)continue;//如果除不尽就跳过
			res = sum / j;//分成的根数
			ans = j;//更新答案
			if(dfs(ans,1,0))
			{
				cout << ans << endl;
			}
		}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值