【题解】洛谷P1120 小木棍(搜索+剪枝+卡常)
洛谷P1120:https://www.luogu.org/problemnew/show/P1120
思路
明显是搜索题嘛
但是这数据增强不是一星半点呐
我们需要N多的剪枝
PS:需要先删去超出50的木棍
首先我们可以想到枚举每个小木棍的长度来搜索
但是直接枚举肯定会超时的 所以我们想到优化剪枝
因为要组成木棍肯定要从被砍开的木棍中的最大值开始枚举到所有木棍总和长(只有一根木棍被砍开)
然而这样却还不是最优的剪枝 因为每根原始小木棍的长度一样 所以枚举长度的时候可以判断是否被总和整除
而且我们只需要枚举到总和的一半即可 因为如果分成两根或以下行不通的话 到最后只需要输出总长就行(只有一根木棍)
因为短的可以组合得比长的更灵活 因此我们可以把木棍从大到小排序之后再选择
进入DFS后我们需要判断如果当前枚举的这根木棍还需要凑的长度为0 且已经满足:凑出的根数已经足够 (凑出长棍的根数=所有木棍的长度之和/原始长度)
当DFS失败时 我们需要退出并换另外一根长度不同的木棍 因为一样长度的可能有很多 所以时间浪费了 我们需要在进入DFS之前预处理出所有木棍下一根不同长度的编号
可以根据木棍长度的单调性来二分找出第一个木棍长度不大于未拼长度rest
参考洛谷某dalao的难想却特别特别重要剪枝:
如果当前长棍剩余的未拼长度等于当前木棍的长度或原始长度,继续拼下去时却失败了,就直接回溯并改之前拼的木棍
解释:
当前长棍剩余的未拼长度等于当前木棍的长度时,当前木棍明显只能自组一根长棍,但继续拼下去却失败,说明这根木棍不能自组?!这根木棍不自组就没法用上了,所以不用搜更短的木棍了,直接回溯,改之前的木棍;
当前长棍剩余的未拼长度等于原始长度时,说明这根原来的长棍还一点没拼,现在正在放入一根木棍。很明显,这根木棍还没有跟其它棍子拼接,如果现在拼下去能成功话,它肯定是能用上的,即自组或与其它还没用的木棍拼接。但继续拼下去却失败,说明现在这根木棍不能用上,无法完成拼接,所以直接回溯,改之前的木棍。
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 70
int n,k,minn,sum,c,num,len;
int mood[maxn],nex[maxn];//nex是预处理编号
bool vis[maxn],flag;
int cinn()
{
int x=,f=;
char ch=;
while(!isdigit(ch))
f|=(ch=='-'),ch=getchar();
while(isdigit(ch))
x=(x<<)+(x<<)+(ch^),ch=getchar();
return f?-x:x;
}
void write(int x)
{
if(x<)putchar('-'),x=-x;
if(x>=)write(x/);
putchar(x%+'');
}
bool cmp(int a,int b)
{
return a>b;
}
void dfs(int p,int last,int rest)//p是当前已经拼倒第几根 last是上一根用的编号 rest是还要多长
{
int i;
if(!rest)//还需要0长度的木棍
{
if(p==num)//如果已经凑齐了所有木棍
{
flag=;
return;
}
for(i=;i<=n;i++)//如果还没凑齐 找一根还没用过的当第一根要用的
if(!vis[i]) break;
vis[i]=;
dfs(p+,i,len-mood[i]);//搜索下一根
vis[i]=;
if(flag) return;
}
int l=last+,r=n,mid;
while(l<r)//二分找编号
{
mid=(l+r)>>;
if(mood[mid]<=rest) r=mid;
else l=mid+;
}
for(i=l;i<=n;i++)//注意从第一根不同的编号开始而不是从1开始
{
if(!vis[i])
{
vis[i]=;
dfs(p,i,rest-mood[i]);
vis[i]=;
if(flag) return;
if(rest==mood[i]||rest==len) return;//最后一个剪枝
i=nex[i];//更换小木棍
if(i==n) return;
}
}
}
void read()
{
n=cinn();
while(n)
{
int x;
x=cinn();
if(x<=)//删去大于50的木棍
{
sum+=x;
mood[++k]=x;
}
n--;
}
n=k;
sort(+mood,+mood+n,cmp);//从大到小排序
minn=mood[];//木棍中的最大值是枚举长度的最小值
nex[n]=n;
for(int i=n-;i>;i--)//预处理编号
{
if(mood[i]==mood[i+]) nex[i]=nex[i+];
else nex[i]=i;
}
}
int main()
{
read();
for(len=minn;len<=sum/;len++)
{
if(sum%len==)//整除
{
num=sum/len;//小木棍根数
flag=;
vis[]=;
dfs(,,len-minn);//取了第一根
vis[]=;
if(flag)
{
write(len);//如果满足输出
return ;
}
}
}
write(sum);//只有一根木棍
}
【题解】洛谷P1120 小木棍(搜索+剪枝+卡常)的更多相关文章
- 洛谷P1120 小木棍 [搜索]
题目传送门 题目描述乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度. 给出每段小木棍 ...
- 洛谷 P1120 小木棍 dfs+剪枝
Problem Description [题目链接] https://www.luogu.com.cn/problem/P1120 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不 ...
- 洛谷P1120 小木棍 [数据加强版](搜索)
洛谷P1120 小木棍 [数据加强版] 搜索+剪枝 [剪枝操作]:若某组拼接不成立,且此时 已拼接的长度为0 或 当前已拼接的长度与刚才枚举的长度之和为最终枚举的答案时,则可直接跳出循环.因为此时继续 ...
- 洛谷P1120 小木棍
洛谷1120 小木棍 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长 ...
- 洛谷 P1120 小木棍 [数据加强版]解题报告
P1120 小木棍 [数据加强版] 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它 ...
- 洛谷——P1120 小木棍 [数据加强版]
P1120 小木棍 [数据加强版] 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过5050. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍 ...
- 洛谷 P1120 小木棍 [数据加强版]
P1120 小木棍 [数据加强版] 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它 ...
- 一本通&&洛谷——P1120 小木棍 [数据加强版]——题解
题目传送 一道特别毒瘤能提醒人不要忘记剪枝的题. 首先不要忘了管理员的话.忘把长度大于50的木棍过滤掉真的坑了不少人(包括我). 显然是一道DFS题 .考虑剪枝. 找找搜索要面临的维度.状态:原始木棍 ...
- 洛谷 P1120 小木棍[数据加强版]
这道题可能是我做过的数据最不水的一道题-- 题目传送门 这题可以说是神剪枝,本身搜索并不算难,但剪枝是真不好想(好吧,我承认我看了题解)-- 剪枝: 用桶来存储木棍 在输入的时候记录下最长的木棍和最短 ...
随机推荐
- [Java反射基础四]通过反射了解集合泛型的本质
本文接上文"方法反射的基本操作",利用反射了解下java集合中泛型的本质 1.初始化两个集合,一个使用泛型,一个不使用 ArrayList list1 = new ArrayLis ...
- lincode 题目记录5
Course Schedule 安排课表 Frog Jump 最长回文字符串长度 Course Schedule 选课方案问题,题目说的很清楚了就是bfs或者dfs,然后加个字典优化,弄了好久没 ...
- jQuery extend方法详解
先说个概念的东西: jQuery为开发插件提拱了两个方法,分别是: $.fn.extend(item):为每一个实例添加一个实例方法item.($("#btn1") 会生成一个 j ...
- 纪念一个神坑——react-native-echarts
一.问题 在rn项目里引用的时候,本该显示图表的界面显示出了一堆html... 二.原因 官方没给配置好 三.解决 1./node_modules/native-echarts/src/compone ...
- 第2章、数据与简单计算程序(c语言入门)
一.写程序描述数据的处理 ①描述数据 ②描述过程 ps:和做鸡蛋饼差不多:数据是材料,作法是过程. 空白符的作用是使用程序更容易了解. 二.标识符 1.基本要求: ①由字母,数字,下划线组成. ②数字 ...
- ArcSDE 10.2 for Oracle 12C安装注意事项
ArcSDE 10.2 for Oracle 12C安装注意事项 1.环境说明 从ArcSDE10.2.1开始支持Oracle 12C. 2.安装注意事项 SDE空间数据库可以安装到PDB中,使用Cr ...
- Keras 时序模型
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/Thinking_boy1992/article/details/53207177 本文翻译自 时序模 ...
- ToolBar 简单使用
ToolBar 简单使用 ToolBar 是在 android 5.0之后推出的一款用来替代 ActionBar 的 View.ActionBar 是Activity的一部分,不能用在其他视图层次上( ...
- AndroidStudio安装教程
Android studio安装与配置 1.首先下载Android studio安装包,可以从http://www.android-studio.org/ 2.下载好该安装包之后,点击进行安装,依次出 ...
- JavaScript Event 事件 事件流 事件对象 事件处理程序 回调函数 error和try...catch和throw
参考资料: 慕课网 DOM事件探秘 js事件对象 处理 事件驱动: JS是采用事件驱动的机制来响应用户操作的,也就是说当用户对某个html元素进行操作的时候,会产生一个事件,该事件会驱动某些函数 ...