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


一道特别毒瘤能提醒人不要忘记剪枝的题。
首先不要忘了管理员的话。忘把长度大于50的木棍过滤掉真的坑了不少人(包括我)。
显然是一道DFS题 。考虑剪枝。
找找搜索要面临的维度、状态:原始木棍的长度len,原始木棍的条数m,当前正在拼第k条原始木棍、还剩下没拼完的长度rest,木根的编号。
去等效冗杂考虑:
1、为了祛除冗杂,我们可以假设拼成一根原始木棍的若干小木棍的长度x1,x2,x3,x4,x5...满足x1<x2<x3<x4<x5<...同时把小木棍的长度从大到小排个序,每次找符合条件的小木棍时都从上一个符合条件的小木棍的后面去找,这样就不会有拼成小木棍长度的序列的元素相同,只因为顺序不同就重复搜索的情况了。
2、注意可能有长度相同的小木棍,当我们试完一个小木棍后,再试长度跟它相同的小木棍时,显然得到的情况是一样的,所以应该试下一个长度不同的小木棍,即跳过长度与它相同的小木棍(这里我用预处理处理出每个小木棍的长度与它相等的最后一根小木棍的编号)。
可行性剪枝考虑:
1、一个非常暴力的思路是从0开始到所有木根长度的总和sum枚举len搜索。显然超时妥妥的,所以考虑优化。发现m一定是个整数,所以len一定是sum的因数。而len只需枚举到sum/2就可以了。因为如果len枚举到sum/2后都没找到答案,那答案只能是所有小木棍拼成一个大木棍的长度。
2、当k==m时,剩下的小木棍的长度总和等于len,即一定能拼成一条原始木棍,所以直接回溯即可。
3、当resti(当前找到的小木棍为i时的rest)正好等于找到的符合条件的小木棍i的长度、并把它拼上,之后却不能把所有原始木棍拼出,那么resti在接下来拼木棍时肯定不能得到答案,所以直接回溯。因为resti拼完时,要么使用小木棍i,要么用几根长度和等于小木棍i的长度的小木棍才能刚好把resti拼完。本来那几根小木棍就不能与剩下的小木棍拼出还要拼的原始木棍,当那几根小木棍换成总长度一样,但个数为1的小木棍i后,不就更不能拼出还要拼的原始木棍了吗?
最优性剪枝考虑:找到答案后立即回溯,其他的操作都不管。
实现优化:
1、当我们在找接下来要用哪条木棍拼时可以用二分查找在第last(一条符合条件的小木棍的编号)+1条到最后一条木棍中第一条长度小于等于rest的木棍。
2、我们在每次回溯时把used数组恢复,而避免用memset(memset用多了,慢到崩溃)
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cctype> using namespace std; bool used[],bj; int a[],n,sum,m,len,nxt[],ans; char ch; bool cmp(int a,int b)
{
return a>b;
} inline int read()//吓得都用快读了
{
ans=;
ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) ans=(ans<<)+(ans<<)+ch-'',ch=getchar();
return ans;
} void dps(const int &k,const int &last,const int &rest)
{
if(k==m) {bj=;return;}//可行性剪枝2
if(!rest)
{
for(int i=;i<=n;i++)
if(!used[i])
{
used[i]=;
dps(k+,i,len-a[i]);
used[i]=;//别忘了回溯,因为可能影响到搜索树的“舅舅节点”。
return;
}
}
int l=last+,r=n,mid;
while(l<r)//
{
mid=(l+r)>>;
if(a[mid]<=rest) r=mid;
else l=mid+;
}
for(int i=l;i<=n;i++)
if(!used[i])
{
used[i]=;
dps(k,i,rest-a[i]);//可行性剪枝3
if(bj) return;//最优性剪枝
used[i]=;
if(rest==a[i]) return;
i=nxt[i];
}
} int main()
{
n=read();
int tot=;
int b;
for(int i=;i<=n;i++)
{
b=read();
if(b<=)
{
a[++tot]=b;
sum+=b;
}
}
n=tot;
sort(a+,a+n+,cmp);
for(int i=n;i>=;i--)//预处理
{
if(a[i]==a[i+]) nxt[i]=nxt[i+];
else nxt[i]=i;
}
int s=sum/;used[]=;
for(len=a[];len<=s;len++)
if(sum%len==)//可行性剪枝1
{
bj=;
m=sum/len;
dps(,,len-a[]);
if(bj)
{
printf("%d",len);
return ;
}
}
if(!bj) cout<<sum;
return ;
}
一本通&&洛谷——P1120 小木棍 [数据加强版]——题解的更多相关文章
- 洛谷 P1120 小木棍 [数据加强版]解题报告
P1120 小木棍 [数据加强版] 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它 ...
- 洛谷——P1120 小木棍 [数据加强版]
P1120 小木棍 [数据加强版] 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过5050. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍 ...
- 洛谷 P1120 小木棍 [数据加强版]
P1120 小木棍 [数据加强版] 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它 ...
- 洛谷—— P1120 小木棍 [数据加强版]
https://www.luogu.org/problem/show?pid=1120 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接 ...
- [洛谷P1120]小木棍 [数据加强版]
题目大意:有一些同样长的木棍,被切割成几段(长$\leqslant$50).给出每段小木棍的长度,找出原始木棍的最小可能长度. 题解:dfs C++ Code: #include<cstdio& ...
- 洛谷P1120 小木棍 [数据加强版]搜索
玄学剪支,正好复习一下搜索 感觉搜索题的套路就是先把整体框架打出来,然后再一步一步优化剪枝 1.从maxv到sumv/2枚举长度(想一想,为什么) 2. 开一个桶,从大到小开始枚举 3. 在搜索中,枚 ...
- P1120 小木棍 [数据加强版] 回溯法 终极剪枝
题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过5050. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度. 给出每段小木棍的长度 ...
- P1120 小木棍 [数据加强版]
题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度. 给出每段小木棍的长度,编 ...
- P1120 小木棍 [数据加强版](poj 1011)
题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度. 给出每段小木棍的长度,编 ...
随机推荐
- LSTM用于MNIST手写数字图片分类
按照惯例,先放代码: import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data #载入数据集 ...
- echars 饼图 --》二次封装
<template> <!-- 饼状图 1. 调用页面引入 import EcharsPie from '@/components/echarsPie.vue'; 注:自定义的组件名 ...
- linux 文件属性文件权限
权限 -rw-------. root root Mar : anaconda-ks.cfg drwxr-xr-x root root May : dir1 drwxr-xr-x root root ...
- windows10下安装pygame并验证成功
首先要确保网络正常 py -m pip install --upgrade pip python -m pip install pygame --user 然后进行验证: py -m pygame.e ...
- 剑指Offer编程题(Java实现)——链表中倒数第k个结点
题目描述 输入一个链表,输出该链表中倒数第k个结点. 注意: 该题目不可以用先反转链表再输出第k个结点的方式,因为反转链表会改变该结点的next指向 思路一 使用栈Stack倒序存储,顺序pop第k个 ...
- QButtonGroup
单选按钮和多选按钮,存放进QButtonGroup中 QButtonGroup方法来实现分组:将相同功能的按键,设为一个分组,然后可以进行 单选 或 多选 或 互斥单选 QAbstractButton ...
- html5酷炫效果链接收集
HTML5 3D图片相册图片轮播动画 http://www.html5tricks.com/demo/html5-3d-gallery-animation/index.html 36种漂亮的CSS ...
- SQL执行计划之sql_trace
一,sql_trace的作用:用以描述SQL的执行过程的trace输出. - SQL是如何操作数据的 - SQL执行过程中产生了哪些等待事件 - SQL执行中消耗了多少资 ...
- ECMAScript 6 学习笔记(二)
ECMAScript 6 let和const命令 let命令 基本用法 ES6新增了let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效. { let a ...
- 理解PHP面向对象三大特性
一.封装性 目的:保护类里面的数据,让类更安全, protected和private只能在类中或子类访问,通过public提供有限的接口供外部访问,封装是控制访问,而不是拒绝访问 封装关键字:publ ...