1月20日 每日一题 UVA-307题解

UVA-307 Sticks

题意
乔治拿了相同长度的木棍,随机切开,直到所有零件的长度最大为50个单位。 现在,他想将木棍恢复到原始状态,但是他忘记了原来拥有多少木棍以及它们原本有多长。 请帮助他,设计一个程序,计算出那些棍子的可能的原始最小长度。 所有以单位表示的长度都是大于零的整数。
输入
输入包含2行。 第一行包含切割后的木棍零件数量,最多为64个木棍。 第二行包含被空格隔开的那些部分的长度。 文件的最后一行包含零。
输出
输出应包含原始木棍的最小长度,每行一根。
Sample Input
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
Sample Output
6
5

题意: ·····恢复到原来的多根相同的木棍(或只有一根),求原来的木棍长度的最小值。

分析:

设: 切开后木棍所有长度 为一个数组 a ,所有的长度和为sum 。
原状态的木棍长度只可能是 [ 数组中的最大值,sum ] 之间能整除sum的数,求最小值就从 这些能整除sum的 的第一个数开始 依次判断该长度x是否满足条件 如满足则原始长度的最小值就是x
(此处 “满足条件” 就是:恰好构成了 num(num=sum/x) 根长度为x的木棍)

过题的关键在 dfs+剪枝 :

  1. 在尽可能靠近跟的地方剪枝:降序排序
  2. 当前一根原始木棍拼凑成功,后面一根拼凑失败就不用继续下去了
  3. 若一根原始木棍中的第一根小木棍不能成功拼凑这一跟原始木棍,就不用继续了

在这里插入图片描述

AC代码

#include <bits/stdc++.h>
using namespace std;

int n,sum,x,num;
int a[70],v[70];
bool cmp(int &a,int &b){return a>b;}

bool dfs(int cnt,int len,int cntnum){//cnt-当前组的第几根,cntnum-到了第几组,len-当前组的长度
	if(cntnum==num)return 1;//枚举所有木棍有解( 构成了num根均为长度x的木棍)
	
	for(int i=cnt;i<n;i++){
		if(v[i] ||( i && !v[i-1] && a[i]==a[i-1]) )continue;//若该木棍被用过 或 该木棍跟前一根木棍一样且前一根没用过 就跳过
		
		if(len+a[i]==x){
			v[i]=1;
			if(dfs(0,0,cntnum+1))return 1;
			v[i]=0;
			return 0;//剪枝2
		}
		else if(len+a[i]<x){
			v[i]=1;
			if(dfs(i+1,len+a[i],cntnum))return 1;
			v[i]=0;
			if(len==0)return 0;//剪枝3
		}
	}
	return 0;//枚举所有木棍都没得到解,返回0
}
int main(){
	while(scanf("%d",&n)){
		if(n==0)break;
		sum=0;
		memset(a,0,n*sizeof(int));
		for(int i=0;i<n;i++){scanf("%d",&a[i]);sum+=a[i];}
		
		sort(a,a+n,cmp);
		for(x=a[0];x<=sum;x++){
			if(sum%x==0){
				num=sum/x;//num为原来木棍根数
				memset(v,0,sizeof(v));
				if(dfs(0,0,0)){break;}
			}
		}
		printf("%d\n",x);
	}
	return 0;
}

如果哪里写错了 或者 有更好的方法 可以私我让我也学习学习

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值