洛谷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 小木棍(搜索+剪枝+卡常)的更多相关文章

  1. 洛谷P1120 小木棍 [搜索]

    题目传送门 题目描述乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度. 给出每段小木棍 ...

  2. 洛谷 P1120 小木棍 dfs+剪枝

    Problem Description [题目链接] https://www.luogu.com.cn/problem/P1120 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不 ...

  3. 洛谷P1120 小木棍 [数据加强版](搜索)

    洛谷P1120 小木棍 [数据加强版] 搜索+剪枝 [剪枝操作]:若某组拼接不成立,且此时 已拼接的长度为0 或 当前已拼接的长度与刚才枚举的长度之和为最终枚举的答案时,则可直接跳出循环.因为此时继续 ...

  4. 洛谷P1120 小木棍

    洛谷1120 小木棍 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50.     现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长 ...

  5. 洛谷 P1120 小木棍 [数据加强版]解题报告

    P1120 小木棍 [数据加强版] 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它 ...

  6. 洛谷——P1120 小木棍 [数据加强版]

    P1120 小木棍 [数据加强版] 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过5050. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍 ...

  7. 洛谷 P1120 小木棍 [数据加强版]

    P1120 小木棍 [数据加强版] 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它 ...

  8. 一本通&&洛谷——P1120 小木棍 [数据加强版]——题解

    题目传送 一道特别毒瘤能提醒人不要忘记剪枝的题. 首先不要忘了管理员的话.忘把长度大于50的木棍过滤掉真的坑了不少人(包括我). 显然是一道DFS题 .考虑剪枝. 找找搜索要面临的维度.状态:原始木棍 ...

  9. 洛谷 P1120 小木棍[数据加强版]

    这道题可能是我做过的数据最不水的一道题-- 题目传送门 这题可以说是神剪枝,本身搜索并不算难,但剪枝是真不好想(好吧,我承认我看了题解)-- 剪枝: 用桶来存储木棍 在输入的时候记录下最长的木棍和最短 ...

随机推荐

  1. 基数排序——Java实现

    一.基数排序思想 相比其它排序,主要是利用比较和交换,而基数排序则是利用分配和收集两种基本操作.基数 排序是一种按记录关键字的各位值逐步进行排序的方法.此种排序一般适用于记录的关键字为整数类型的情况. ...

  2. java web 开发入门

    Java web,是java技术用来解决web互联网领域的技术总和.Java web技术主要包括客户端和服务端,java在客户端的服务有java applet,不过用的非常少,大部分应用在服务端,比如 ...

  3. Grunt完整打包一个项目实例

    Grunt确实好用,配置好Gruntfile.js之后,一个命令就行云如流水,程序帮你搞定一切,爽歪歪. 我们先看压缩前的目录: 再看打包后的目录: build是打包后的文件夹,main.css是压缩 ...

  4. 关于纯css写三角形在firefox下的锯齿问题

    相信很多人都用过利用border来实现小三角箭头,百度一下,这类的文章多如牛毛,这里我还是啰嗦点把常用的方法陈列出来: .triangle_border_up{ width:; height:; bo ...

  5. hdu 1159 Common Subsequence(LCS)

    Common Subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  6. JDBC URL格式定制

    数据库URL制定: 当加载的驱动程序,可以建立程序中使用DriverManager.getConnection()方法的连接.为方便参考,让列出了三个重载DriverManager.getConnec ...

  7. Azkaban调度器

    Azkaban介绍 Azkaban 是由 Linkedin 公司推出的一个批量工作流任务调度器,用于在一个工作流内以一个特定的顺序运行一组工作和流程.Azkaban 使用 job 配置文件建立任务之间 ...

  8. SQL点点滴滴_常用函数

    该文章转载自http://www.cnblogs.com/jiajiayuan/archive/2011/06/16/2082488.html 别人的总结,很详细. 以下所有例子均Studnet表为例 ...

  9. Day02——Python基本数据类型

    一.运算符 1.算数运算符 2.比较运算符 3.复制运算符 4.逻辑运算符 5.成员运算符 二.基本数据类型 1.数字 整数(int) 在32位机器上,整数的位数为32位,取值范围为-2**31-2* ...

  10. Python学习---重点模块之shelve

    简单示例 import shelve f = shelve.open(r'shelve.txt') f['info'] = {'name':'ftl', 'age':23, 'sex': 'male' ...