C++木棍

该博客介绍了一道C++编程题,题目要求帮助小Z计算出经过切割后的木棍最小的原始长度。输入包含切割后的木棍数量和长度,需要找到满足条件的最小原始长度,使所有棍子的长度都能被原始长度整除。解题思路包括枚举原始长度、搜索拼接方法,并通过剪枝优化搜索过程,避免重复搜索和无效尝试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

木棍

题目描述
小Z拿出长度相同的一些原始棍子并进行随意的切割,直到所有切割出的小棍子的长度都不大于50个单位。现在他想把棍子恢复成原来的状态,但是他忘记了原来有多少根棍子也忘记了原来棍子的长度是多少。

请你帮助他编写一个程序,计算出这些棍子最小的原始长度。所有棍子的长度都是大于0的整数。

输入格式
输入包含多组数据,对于每组数据包含两行。

第一行,切割完成的木棍的数量,最多64根

第二行,用空格隔开的整数,分别表示这些棍子的长度

当输入为0时,表示输入结束

输出格式
对于每组数据输出一行,一个整数表示棍子最小的原始长度

输入输出样列
输入样例1:
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
输出样例1:
6
5
【耗时限制】1000ms 【内存限制】128MB

解题思路
设n根小木棍的长度分别为L1,L2,L3……Ln;则原始木棍的长度为:len∑[max(Li),sum(Li)];

枚举:从小到大枚举原始木棍的可能长度len,判断len是否满足要求。

如何判断len是否满足要求?

  1. 木棍总长度sum必须能被len整除,原始小木棍的数量num=sum/len;
  2. 找到一种使用n根小木棍拼凑出num个长度为len的原始木棍方法。

搜索找到一种使用n根小木棍拼凑出num个长度为len的原始木棍的方法。

●相当于向num个盘子里面放棍子,保证每个盘子里棍子长度的累加和都是len。


到达目的地
可选范围:从1到第n根中,所有还未使用过的小棍子;
可行性剪枝:拼凑第cur根原始棍子时,已拼凑的长度+待选棍子长度>num则剪枝;
时间复杂度O(n!)

#include<bits/stdc++.h>
using namespace std;
const int N=80;
int n,sticks[N],num,len,tot,maxlen;
bool vis[N];
bool dfs(int cur,int sum){
   
   
	if(cur>num)return true;
	if(sum==len)return dfs(cur+1,0);
	for(int i=1;i<=n;i++){
   
   
		if(!vis[i]&&sum+sticks[i]<=len){
   
   
			vis[i]=true;
			if(dfs(cur,sum+sticks[i]))return true;
			vis[i]=false;
		}
	}
	return false;
}
int main()
{
   
   
	while(cin>>n&&n){
   
   
		tot=maxlen=0;
		memset(vis,0,sizeof(vis));
		for(int i=1;i<=n;i++){
   
   
			cin>>sticks[i];
			maxlen=max(maxlen,sticks[i]);
			tot+=sticks[i];
		}
	}
	for(len=maxlen;len<=tot;len++){
   
   
		if(tot%len!=0)continue;
		num=tot/len;
		if(dfs(1,0))break;
		cout<<len<<endl;
	}
	return 0;
}

解决重复搜索问题。

在搜索拼接原始木根时,同一组小木棍会重复搜索
例:len=6时,在拼接第1根原始木棍时,尝试完(1)(3)后还会尝试(3)(1);

在这里插入图片描述
在搜索拼接原始木棍时,不同的原始木棍会重复使用相同的小木棍
例:len=6时,第1根棍子选(1)(3),第2根棍子选(4)(6);反之亦可;
排除等效赘余
用来拼接同一根原始木棍的小木棍,按照编号严格递增:即(1)(3)可以,(3)(1)不可以。

用来拼接第cur根原始木棍的第1根小木棍的编号严格大于cur-1根原始木棍的第1根小木棍,(1)(3),(4)(6)可以,(4)(6),(1)(3)不可以。

#include<bits/stdc++.h>
using 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值