典型的深搜+剪枝策略

我们采用可行性剪枝、上下界剪枝、优化搜索顺序剪枝、最优性剪枝的方面来帮助我们进行剪枝。

也许有人还不知道剪枝,那我就弱弱地为大家补习一下吧qwq:

.优化搜索顺序:
在一些搜索问题中,搜索树的各个层次、各个分支之间的顺序是不固定的。不同的搜索顺序会产生不同的搜索树形态,其规模大小也相差甚远。因此,我们可以采用排序、更改等手段来优化时间或者空间上的复杂度,借此来优化我们的程序。
.排除等效冗余
在搜索过程中,如果我们能够判定从搜索树的当前节点沿着某几条不同的分支到达的子树是等效的,那么只需要对于其中的一条分支进行搜索。这中优化的方法应用的时候十分有效(而且只需要一个"=="qwq)。
.可行性剪枝
在搜索过程中,及时对当前状态进行检查,如果发现分支已经无法到达递归的边界,就执行回溯。这就好比我们在道路上行走时,远远地看到前方是一个死胡同,就应该立即折返绕路,而不是走到这个死胡同的尽头再返回。
某些题目的范围限制是一个区间,此时可行性剪枝也被称为"上下界剪枝"。
.最优性剪枝
在最优化问题的搜索过程中,如果当前花费的代价已经超过当前搜索到的最优解,那么无论采取多么优秀的策略到达递归边界,都不可能更新答案。此时可以停止对当前分支的搜索,执行回溯。
.记忆化
可以记录每个状态的搜索结果,在重复遍历一个状态时直接检索并返回。这好比我们对图进行深度优先遍历时,标记一个节点是否已经被访问过。(类似于visit[],或者像线段树懒标记之类的.我是这么理解的qwq)

题目背景

7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层

生日蛋糕,每层都是一个圆柱体。

设从下往上数第i(1<=i<=M)层蛋糕是半径为Ri, 高度为Hi的圆柱。当i<M时,要求R_i>R_{i+1}Ri​>Ri+1​且H_i>H_{i+1}Hi​>Hi+1​。

由于要在蛋糕上抹奶油,为尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)的面积Q最小。

令Q= Sπ

请编程对给出的N和M,找出蛋糕的制作方案(适当的Ri和Hi的值),使S最小。

(除Q外,以上所有数据皆为正整数)

题目描述

输入输出格式

输入格式:

有两行,第一行为N(N<=20000),表示待制作的蛋糕的体积为Nπ;第二行为M(M<=15),表示蛋糕的层数为M。

输出格式:

仅一行,是一个正整数S(若无解则S=0)。

样例

输入样例:


输出样例:

   68

下面我们进行一下这个问题的求解思路:

1.上下界剪枝:

当我们在第dep层的时候,我们只在下面的范围枚举半径和高度即可。

首先,枚举R∈[dep,min($\sqrt{N-v}$,r[dep+1]-1)];

其次,枚举H∈[dep,min($\sqrt{N-v}/R^2$,h[dep+1]-1)];

2.优化搜索顺序

在上面确定的范围中进行倒序枚举。

3.可行性剪枝(画个五角星)

可以预处理出从上往下前i(1≤i≤M)层的最小体积和侧面积。

显然,当第1~i层的半径分别取1,2,3···i时,有最小体积和侧面积。

如果当前体积V加上1~dep-1层的最小体积大于N,则可以剪枝。

4.最优性剪枝(1)

如果当前表面积s加上1~dep-1层的最小侧面积大于已经搜到的结果,剪枝。

5.最优性剪枝(2)

利用h和r数组,1~dep-1层的体积可表示为n-v=∑(dep-1,k=1)h[k]*r[k]^2,1~dep层的表面积可以表示为2∑(dep-1,k=1)h[k]*r[k]。

因为2∑(dep-1,k=1)h[k]*r[k]=2/r[dep]*∑(dep-1,k=1)h[k]*r[k]*r[dep]≥2/r[dep]*∑(dep-1,k=1)h[k]*r[k]^2≥2(n-v)/r[dep]。

所以当2(n-v)/r[dep]+s大于已经搜到的结果时,可以剪枝。

加上以上五个剪枝后,搜索算法就可以快速求出该问题的最优解。

完整代码如下:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int r[],h[],n,m,dep,minn=0x7fffffff;
void dfs(int dep,int leftdep,int leftv,int nowv)
{
if(leftv<)
return ;
if(dep>m+)
return ;
if(nowv>=minn)
return ;
if(leftv==&&dep==m+)
{
nowv+=r[]*r[];
minn=min(nowv,minn);
return ;
}
if(nowv+leftdep+r[]*r[]>minn)
return ;
if(leftv-(r[dep-]*r[dep-]*h[dep-]*leftdep)>)
return ;
for(int i=r[dep-]-;i>=leftdep;i--)
for(int j=h[dep-]-;j>=leftdep;j--)
{
if(leftv-i*i*j>=&&dep<=m)
{
r[dep]=i;
h[dep]=j;
dfs(dep+,leftdep-,leftv-i*i*j,nowv+(*i*j));
r[dep]=;
h[dep]=;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
r[]=sqrt(n);
h[]=sqrt(n);
dfs(,m,n,);
if(minn==0x7fffffff)
{
printf("");
return ;
}
printf("%d",minn);
return ;
}

写完了长长的博文,下面来总结一下心得吧qwq:

1.搜索算法面对的状态我们可以将其理解为一个岔路口的选择问题,也就是可以看作一个多元组,其中每一元都是问题状态空间中的一个"维度"。

这其中每一个维度发生变化,都会移动状态空间中的一个"点"。

而这些维度通常在题目中也会出现,这些便需要大家在做题的时候多留心观察一下我们所需要的条件以及我们根据这些维度的变化能够得到什么,从而得出合理的搜索框架。

2.搜索过程中的剪枝,其实我们就是针对于每一个"维度"与其该维度的边界条件,加以缩放、推导,得出一个相应的不等式,以减少搜索树的扩张从而达到优化复杂度的目的。

3.为了进一步提高我们剪枝的"效率"以及我们的所要求的目的,我们可以除了对当前所花费的代价之外,也对该状态未来的"状态"进行分析,有时我们还可以跨维度进行优化分析,达到我们的要求(也就是全面优化qwq),同时这也更容易接近我们的目的。

手写不易,各位客官点个赞呗(花花)

[洛谷P1731][NOI1999]生日蛋糕(dfs)(剪枝)的更多相关文章

  1. 洛谷 P1731 [NOI1999]生日蛋糕(搜索剪枝)

    题目链接 https://www.luogu.org/problemnew/show/P1731 解题思路 既然看不出什么特殊的算法,显然是搜索... dfs(u,v,s,r0,h0)分别表示: u为 ...

  2. 洛谷——P1731 [NOI1999]生日蛋糕

    P1731 [NOI1999]生日蛋糕 搜索+剪枝 常见的剪枝: 若当前状态+后面所要搜索的最差的状态$>$或是$<$最后的状态,就返回 预处理最差的状态 #include<iost ...

  3. 【题解】洛谷P1731 [NOI1999] 生日蛋糕(搜索+剪枝)

    洛谷P1731:https://www.luogu.org/problemnew/show/P1731 思路 三重剪枝 当前表面积+下一层表面积如果超过最优值就退出 当前体积+下一层体积如果超过总体积 ...

  4. 洛谷 P1731 [NOI1999]生日蛋糕

    P1731 [NOI1999]生日蛋糕 题目背景 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层 生日蛋糕,每层都是一个圆柱体. 设从下往上数第i(1<=i<=M ...

  5. C++ 洛谷 P1731 [NOI1999]生日蛋糕

    P1731 [NOI1999]生日蛋糕 一本通上也有. 这TM是一道极其简单的深搜剪枝(DP当然可以的了,这里我只讲深搜). 首先圆柱公式:(有点数学基础都知道) V=πR2H S侧=π2RH S底= ...

  6. 洛谷 P1731 [NOI1999]生日蛋糕 && POJ 1190 生日蛋糕

    题目传送门(洛谷)  OR 题目传送门(POJ) 解题思路: 一道搜索题,暴力思路比较容易想出来,但是这道题不剪枝肯定会TLE.所以这道题难点在于如何剪枝. 1.如果当前状态答案已经比我们以前某个状态 ...

  7. POJ1190 洛谷P1731 NOI1999 生日蛋糕

    生日蛋糕(蛋糕是谁?) Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20272   Accepted: 7219 Desc ...

  8. 洛谷P1731 [NOI1999]生日蛋糕(爆搜)

    题目背景 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层 生日蛋糕,每层都是一个圆柱体. 设从下往上数第i(1<=i<=M)层蛋糕是半径为Ri, 高度为Hi的圆柱 ...

  9. 洛谷 P1731 [NOI1999]生日蛋糕 题解

    每日一题 day53 打卡 Analysis 观察一个蛋糕的俯视图,上表面的面积其实就是最下面那一层的底面积,所以在第一次搜索的时候加入这个底面积,之后就只用考虑侧面积就好啦. 就是每次枚举r和h,如 ...

随机推荐

  1. Activity生命周期详解

    http://blog.csdn.net/liuhe688/article/details/6733407 onPause 回到 onResume 的过程“在一般的开发中用不上”,但是作为开发者还是有 ...

  2. log4j日志日记记录使用教程

    注意:每次引入Logger的时候注意引入的jar包,因为有Logger的包太多了...... Logger必须作为类的静态变量使用.原因如下: 1 使用static修饰的属性是归这个类使用的2 也就是 ...

  3. python cookbook 笔记三

    分组: rows = [ {'address': '5412 N CLARK', 'date': '07/01/2012'}, {'address': '5148 N CLARK', 'date': ...

  4. char *与const char **函数参数传参问题

    传参方法 ## 函数 extern void f2 ( const char ** ccc ); const char ch = 'X'; char * ch_ptr; const char ** c ...

  5. 【Connection Events】【BLE】【原创】

    Connection Events  本人在TI官网的学习笔记,现整理如下   两台BLE设备建立连接后,所有的通信事件都是通过Connection Events中发生的           上图为两 ...

  6. 001_vagrant利器

    一. 这是一个关于Vagrant的学习系列,包含如下文章: Vagrant入门 http://www.cnblogs.com/davenkin/p/vagrant-virtualbox.html 创建 ...

  7. 基于TLS的EAP 认证方法

    TLS: transport level security , 安全传输层协议,用于在两个通信应用程序之间提供保密性和数据完整性.该协议由两层组成: TLS 记录协议(TLS Record)和 TLS ...

  8. centos6中创建软raid方法

    raid概述: 组建raid阵列命令: mdadm:模式化的工具 /etc/mdadm.conf     -A  Assemble 装配模式     -C  Create 创建模式     -C:专用 ...

  9. [学习笔记]Java代码中各种类型变量的内存分配机制

    程序运行时,我们最好对数据保存到什么地方做到心中有数.特别要注意的是内存的分配.有六个地方都可以保存数据: (1) 寄存器 这是最快的保存区域,因为它位于和其他所有保存方式不同的地方:处理器内部.然而 ...

  10. Go语言规格说明书 之 通道 发送语句(send) 和 接收操作符(receive)

    go version go1.11 windows/amd64 本文为阅读Go语言中文官网的规则说明书(https://golang.google.cn/ref/spec)而做的笔记,介绍Go语言的 ...