前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【题解】小木棍(搜索剪枝)

【题解】小木棍(搜索剪枝)

作者头像
fishhh
发布于 2022-08-30 11:31:39
发布于 2022-08-30 11:31:39
40800
代码可运行
举报
文章被收录于专栏:OI算法学习笔记OI算法学习笔记
运行总次数:0
代码可运行

题目描述

乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过 50。

现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。

给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。

输入格式

第一行是一个整数 n,表示小木棍的个数。 第二行有 n 个整数,表示各个木棍的长度

输出格式

输出一行一个整数表示答案。

输入输出样例

输入 #1

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
9
5 2 1 5 2 1 5 2 1

输出 #1

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
6

说明/提示

对于全部测试点,

题目分析

​ 给定若干个木棍的长度,他们是由一些一样长的木棍砍断得到的,要求求出原始木棍的最小可能长度。

​ 首先,暴力搜索。尝试将所有的木棍进行拼接。可以给定一个假想的原始木棍长度ori,原始木棍的长度范围是

搜索尝试能否将小木棍进行拼接成若干根长度为ori的长木棍。设dfs(ori,now,re) 表示原始木棍长ori,当前的长木棍还剩now需要拼接,还剩re根木棍需要拼接。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void dfs(int ori,int now,int re){//拼接目标 剩下的木棍数量
	if(now==0){//一根长木棍拼接成功
		if(re==0){//所有小木棍都用完
			printf("%d",ori);//输出答案
			exit(0);			
		}else{
			dfs(ori,ori,re);//继续再拼下一个长木棍
			return ;
		}
	}
	for(int i=1;i<=n;i++){//遍历所有的木棍
		if(!vis[i]&&a[i]<=now){//找到能用的小木棍
			vis[i]=true;
			dfs(ori,now-a[i],re-1);//递归,拼接下一根
			vis[i]=false;
		}
	}
}

会出现多个点超时。此时,我们考虑进行剪枝。

  1. 原始木棍的长度一定是总长的因子
  2. 可能出现相同的小木棍,当长度a[i]不满足要求了,和他长度相同的小木棍也一定不满足要求
  3. 木棍越短,能够拼的可能性也就越多,可以先从长的小木棍开始拼接,减少搜索次数
  4. 如果搜索后发现长度不合适,且剩余长度等于原始木棍长度,说明之前的选择有问题,可以直接回溯。因为长木棍直接拼上去不合适的话,后面的小木棍无论如何也不可能符合要求。
  5. 如果搜索后发现长度不合适,且该长度等于剩余长度

代码实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
int a[70],n;
bool vis[70];
int cnt[70],nxt[70],les[5000];
void dfs(int ori,int now,int re,int len){//拼接目标 现在差的长度 剩下的木棍数量 
	//	printf("ori:%d now:%d re:%d len:%d\n",ori,now,re,len);
	if(now==0){//拼完一根原始木棍
		dfs(ori,ori,re-1,a[1]);//继续再拼
		return ;
	}
	if(re==0){//全部拼完
		printf("%d",ori);
		exit(0);
	}
	//剪枝3 寻找时,从大到小去找小木棍
	//找到小木棍中小于等于剩余长度的最大长度
	len=min(len,now);
	while(len&&cnt[len]==0) len=les[len];
	
	while(len){
		if(cnt[len]){
			cnt[len]--;
			dfs(ori,now-len,re,len);
			cnt[len]++;
			//剪枝4、5 
			if(now==ori||now==len) return;
			len=nxt[len];//剪枝2 跳过相同木棍,找下一个小木棍
		}else{
			len=nxt[len];
		}
	}
}
int main(){
	int sum=0;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		sum+=a[i];//求和
		cnt[a[i]]++;//记录a[i]个数
	}
	sort(a+1,a+1+n,greater<int>());//从大到小排序
	//预处理,nxt[x] 长度小于x的下一个值
	for(int i=n;i>=1;i--){
		if(a[i]!=a[i+1]){
			nxt[a[i]]=a[i+1];
		}
	}
	//预处理 les[x] 小于x的小木棍的最大的长度
	for(int i=sum,j=a[1];i>=a[n];i--){
		if(i>j){
			les[i]=j;
		}else{
			j=nxt[j];
			les[i]=j;
		}
	}
	for(int i=a[1];i<=sum/2;i++){//从最长的小木棍开始找起
		if(sum%i) continue;//剪枝1 长度不是总长的因数不予考虑
		dfs(i,i,sum/i,a[1]);
	}
	printf("%d",sum);
	return 0;
}

Q.E.D.

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
试题 算法训练 小木棍
资源限制 内存限制:256.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s 问题描述   RJ有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过 50。现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。   给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。 输入格式   第一行为一个单独的整数 N 表示看过以后的小木柜的总数,其中 N<=60;
GeekLiHua
2025/01/21
580
挑战程序竞赛系列(31):4.5剪枝
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014688145/article/details/76550373
用户1147447
2019/05/26
4490
LeetCode 第 201 场周赛(304/5614,前5.42%)
全国排名: 304 / 5614,5.42%;全球排名: 956 / 15616,6.12%
Michael阿明
2021/02/19
4260
#628 DIV2 题解
组样例,每组给一个和个数 。将同一个序列重复次得到一个新序列,问可以从新序列中严格最长上升子序列长度为多少。
ACM算法日常
2020/04/08
2520
#628 DIV2 题解
poj 1011 Sticks (DFS+剪枝)
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.
全栈程序员站长
2022/07/10
2230
poj 1011 hdoj 1455 Sticks(搜索+剪枝)
令initlen为所求的最短原始棒长,maxlen为给定的棒子堆中最长的棒子,sumlen为这堆棒子的长度之和,那么initlen必定在范围[maxlen,sumlen]中,
xindoo
2021/01/22
2440
P1120 小木棍 [数据加强版]
题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50。 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。 给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。 输入输出格式 输入格式: 输入文件共有二行。 第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤65 (管理员注:要把超过50的长度自觉过滤掉,坑了很多人了!) 第二行为N个用空个隔开的正整数,表示N根小木棍的长度。 输出格式: 输出文件仅一行,表示要求的原始木棍
attack
2018/04/12
7190
《算法竞赛进阶指南》0x23 剪枝
比如一个非最优的问题边界,在搜索到最后一层才识别出来舍掉,和搜索到中途就识别出来舍掉,这就是优化搜索顺序的好处
一只野生彩色铅笔
2022/10/31
4840
《算法竞赛进阶指南》0x23 剪枝
Sticks(UVA - 307)【DFS+剪枝】
1.这道题题意就是说原本有一些等长的木棍,后来把它们切割,切割成一个个最长为50单位长度的小木棍,现在想让你把它们组合成一个个等长的大木棍,要求这个拼接成的大木棍的长度最小。问最小长度是多少。(注意,在接下来的介绍中,将最后的大木棍表述为拼接木棍,小木棍还是叫小木棍)
_DIY
2020/10/19
5000
【题解】吃奶酪(剪枝优化+状态压缩)
房间里放着 n 块奶酪。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在 (0,0) 点处。
fishhh
2022/08/30
3740
【题解】吃奶酪(剪枝优化+状态压缩)
poj 2362 hdoj 1518 Square(搜索)
本题大致做法就是对所有小棒子长度求和sum,sum就是正方形的周长,sum/4就是边长side。
xindoo
2021/01/22
2230
hotumoyi吉他_木棒能做什么
乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过 50 个长度单位。
全栈程序员站长
2022/09/22
5130
2017.9.17校内noip模拟赛解题报告
预计分数:100+60+60=220 实际分数:100+60+40=200 除了暴力什么都不会的我。。。。。 T1 2017.9.17巧克力棒(chocolate) 巧克力棒(chocolate) Time Limit:1000ms Memory Limit:64MB 题目描述 LYK 找到了一根巧克力棒,但是这根巧克力棒太长了,LYK 无法一口吞进去。 具体地,这根巧克力棒长为 n,它想将这根巧克力棒折成 n 段长为 1 的巧克力棒,然后 慢慢享用。 它打算每次将一根长为 k 的巧克力棒折成两段长为 a
attack
2018/04/12
9080
几道暑期实习笔试题
DFS 回溯法,先判断组成三连对和组成顺子需要的次数,递归深度 k 就是次数。对于对子和单张的可以直接通过枚举数需要打多少次。可以在组成三连对和顺子的时候增加剪枝操作加快运算:如果构不成三连对或者顺子,则不用进行回溯。
echobingo
2020/08/28
1.3K0
几道暑期实习笔试题
POJ 1011 Sticks
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/118378.html原文链接:https://javaforall.cn
全栈程序员站长
2022/07/13
1680
2020疫情防控考试题(附答案)文库_noip2021初赛答案
有一棵n个节点的,根为1的带权树和m支军队。现在有m支军队已经在某些点上,移动一支军队到一个相邻的点所花时间等于该条边的边权。军队可同时移动。问至少多少时间才可以使从1开始都到不了任何一个叶子节点(无法满足条件输出-1,根节点不能停军队)。
全栈程序员站长
2022/09/23
4300
2020疫情防控考试题(附答案)文库_noip2021初赛答案
长链剖分入坑记
常见的树剖有两种——重链剖分和长链剖分. 它们的区别在于对于preferred son (偏向的孩子节点)的选择标准不同.
ACM算法日常
2020/03/26
4760
长链剖分入坑记
CCPC 2021 哈尔滨站
A_i = 2^{i-1} \bmod M,给出 A,找出模数。如果模数不唯一,则无解。
Clouder0
2022/11/01
1.4K0
超超超高频面试题,快来混个脸熟(一)
此份试题来自民间面经、code top 网站以及部分官方渠道,命中率超高,可以混个脸熟
ACM算法日常
2021/09/07
2520
搜索专题
POJ  Best Sequence http://poj.org/problem?id=1699 题意:给你n个字符窜,求其所能拼接的最短长度。 分析:预处理下,dp[i][j]表示j接在i后头的最
用户1624346
2018/04/17
8190
相关推荐
试题 算法训练 小木棍
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验