洛谷 P1731 [NOI1999]生日蛋糕(搜索剪枝)
题目链接
https://www.luogu.org/problemnew/show/P1731
解题思路
既然看不出什么特殊的算法,显然是搜索。。。
dfs(u,v,s,r0,h0)分别表示:
u为已经搜完的层数,v是现在的体积(不包括这一层),s是现在的表面积(所求的)(不包括这一层),r0是当前层的最大半径,h0是当前层的最大高度。
不加剪枝的dfs。。。(TLE!!!!)
本题的难点
剪枝
- 剪枝1:搜索到每一层时,如果当前的体积加上剩下层(包含当前层)的最小体积还是大于要求的总体积时,必须return,因为不论如何体积总不能符合要求。
- 剪枝2:搜索到每一层时,如果当前表面积加上剩下层(包含当前层)的最小表面积还是大于已经求出来的答案时,return,因为此答案一定不是最优解。
- 剪枝3:首先剪掉的是每一层的半径r和高h的范围。因为Ri>Ri+1且Hi>Hi+1,也就是说,较上层的半径和高一定比下层的小,所以很显然,每一层的半径高度小于上一层的半径和高度并且大于等于m-u(m为总层数,u为搜索完的层数,m-u就是剩下的层数(包括这一层) )。
下面就是要探讨如何进行这三个剪枝:
求剩下层(设为k)的最小体积时,采用递推的方法,由剩下的k-1层的最小体积加上本层的最小体积(i*i*i)。我们用va[i]表示从上往下数前i层的最小体积和,但要注意并不是前i层的最小体积和,因为本题规定的是从下往上数层数。所以实际用时要用v+va[m-u]。
经过一步步的写(kan)证(ti)明(jie),以下的内容显然成立:剩下层(包含当前层)的最小表面积就小于等于2*(n-v)/r。其中n是总体积,v是现在的体积(不包含当前层),r是当前层的最大半径。为什么是小于等于呢?因为为了保证剪枝的正确性,即使少剪几个,也不能把正确的答案剪去。
总结:剪枝要用最好的打算去进行启发式剪枝。即为了保证剪枝的正确性,即使少剪几个,也不能把正确的答案剪去。
剩下的就是细节处理了,例如在dfs函数中枚举的r和h的值,为什么要倒序呢?因为很显然,在体积一定的情况下,半径越大,侧表面积就越小,能在剪枝2中,剪去更多的枝。(多读几遍,感性理解一下)。
看代码(详细注解):
#include<iostream>
#include<cmath>
using namespace std;
const int INF=0x3f3f3f;//一个很大的数
int n,m;
int va[];//va[i]表示从上往下数前i个数的最小体积和。(并不是第i层)
int ans;
void dfs(int u,int v,int s,int r0,int h0){
//u为已经搜完的层数,v是现在的体积,s是现在的表面积(所求的)
//r0是当前层的最大半径,h0是当前层的最大高度。
if(u==m){ //如果已经搜完
if(v==n){ //如果找到答案,更新ans的值
ans=min(ans,s);//取最小值
}
return; //无论是不是答案,都要return
}
if(va[m-u]+v>n) return;
//剪枝1:如果当前的体积加上剩下层(包含当前层)的最小体积还是大于要求的总体积时,必须return,因为不论如何体积总不能符合要求。
if(2.0*(n-v)/r0+s>ans) return;
//剪枝2:如果当前表面积加上剩下层(包含当前层)的最小表面积还是大于已经求出来的答案时,return,因为此答案一定不是最优解。
for(int r=r0;r>=m-u;r--){ //从最大值倒着循环速度会快些
for(int h=h0;h>=m-u;h--){
//剪枝3:缩小每一层的体积和高的范围:从r0、h0到m-u。
int tv=v+r*r*h; //tv是现在的体积,就等于原来的体积加上这一层的体积
if(tv>n) continue; //边界
int ts=s+*r*h; //ts为现在的表面积,等于原来的表面积加上这一层的侧表面积
if(u==) ts+=r*r; //如果是底层,还要再加上上表面积
dfs(u+,tv,ts,r-,h-);
//继续递归下去:层数+1,现在的体积,现在的表面积,下一层的最大体积和表面积
}
}
}
int main()
{
cin>>n>>m;
for(int i=;i<=m;i++){
va[i]=va[i-]+i*i*i;//i*i*i是每一层的最小体积
}
int r0=sqrt(n)+0.5;//r0是最大的半径
ans=INF;//先给ans赋初值
dfs(,,,r0,n);
if(ans==INF) ans=;//无答案输出0
cout<<ans<<endl;
return ;
}
//NOI1999 Day1 t3
洛谷 P1731 [NOI1999]生日蛋糕(搜索剪枝)的更多相关文章
- [洛谷P1731][NOI1999]生日蛋糕(dfs)(剪枝)
典型的深搜+剪枝策略 我们采用可行性剪枝.上下界剪枝.优化搜索顺序剪枝.最优性剪枝的方面来帮助我们进行剪枝. 也许有人还不知道剪枝,那我就弱弱地为大家补习一下吧qwq: .优化搜索顺序: 在一些搜索问 ...
- 洛谷——P1731 [NOI1999]生日蛋糕
P1731 [NOI1999]生日蛋糕 搜索+剪枝 常见的剪枝: 若当前状态+后面所要搜索的最差的状态$>$或是$<$最后的状态,就返回 预处理最差的状态 #include<iost ...
- 【题解】洛谷P1731 [NOI1999] 生日蛋糕(搜索+剪枝)
洛谷P1731:https://www.luogu.org/problemnew/show/P1731 思路 三重剪枝 当前表面积+下一层表面积如果超过最优值就退出 当前体积+下一层体积如果超过总体积 ...
- 洛谷 P1731 [NOI1999]生日蛋糕
P1731 [NOI1999]生日蛋糕 题目背景 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层 生日蛋糕,每层都是一个圆柱体. 设从下往上数第i(1<=i<=M ...
- C++ 洛谷 P1731 [NOI1999]生日蛋糕
P1731 [NOI1999]生日蛋糕 一本通上也有. 这TM是一道极其简单的深搜剪枝(DP当然可以的了,这里我只讲深搜). 首先圆柱公式:(有点数学基础都知道) V=πR2H S侧=π2RH S底= ...
- 洛谷 P1731 [NOI1999]生日蛋糕 && POJ 1190 生日蛋糕
题目传送门(洛谷) OR 题目传送门(POJ) 解题思路: 一道搜索题,暴力思路比较容易想出来,但是这道题不剪枝肯定会TLE.所以这道题难点在于如何剪枝. 1.如果当前状态答案已经比我们以前某个状态 ...
- 洛谷P1731[NOI1999]生日蛋糕
题目 搜索+剪枝,主要考察细节和搜索的顺序,首先可以发现所有数据均为整数,所以初始化每层的蛋糕R和H是整数,然后从高层向低层搜索,然后预处理出各层向低层的最小面积和体积用来剪枝. 就可以每层从当前最大 ...
- POJ1190 洛谷P1731 NOI1999 生日蛋糕
生日蛋糕(蛋糕是谁?) Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 20272 Accepted: 7219 Desc ...
- 洛谷P1731 [NOI1999]生日蛋糕(爆搜)
题目背景 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层 生日蛋糕,每层都是一个圆柱体. 设从下往上数第i(1<=i<=M)层蛋糕是半径为Ri, 高度为Hi的圆柱 ...
随机推荐
- 启动ZOOKEEPER之后能查看到进程存在但是查不到状态,是因为。。。
一般我们在启动ZOOKEEPER之后能查看到进程并且能查到每个节点的状态,但是新手偶尔会遇到查不到状态的问题,这里主要说一下我自己遇到的问题. 是因为myid重复了.... 错误:总共三个节点,mas ...
- Taro -- 定义全局变量
Taro定义全局变量 方法1:在taro中 getApp()只能取到一开始定义的值,并不能取到改变后的值 // app.js文件中 class App extends Component { cons ...
- nginx中break和last的区别
一.环境准备 资源文件创建 mkdir -p /opt/tmp/wqy/test/aaa mkdir -p /opt/tmp/wqy/test/bbb echo "aaa" > ...
- 2014-03-01 春季PAT 1073-1076解题报告
今天下午的PAT考试状态不理想,回来怒刷了一遍,解题报告如下: 1073. Scientific Notation (20) 基本模拟题,将一长串的科学计数转换为普通的数字表示方式.思路是是数组存储输 ...
- Intellij IDEA 插件开发秘籍
来这里找志同道合的小伙伴! 这里总结一下 Intellij IDEA 插件开发的知识,供大家参考,本篇文章包含以下内容: 开发环境搭建 Component 介绍 Extension Point And ...
- windowserver 常用命令
1.查看端口占用: netstat -ano | findstr "服务端口号"2.查看程序运行id: tasklist | findstr nginx 3.杀死进程 tskk ...
- bzoj4408 [Fjoi 2016]神秘数 & bzoj4299 Codechef FRBSUM 主席树+二分+贪心
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4299 https://lydsy.com/JudgeOnline/problem.php?id ...
- 前端每日实战:35# 视频演示如何把 CSS 径向渐变用得出神入化,只用一个 DOM 元素就能画出国宝熊猫
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/odKrpy 可交互视频教程 此视频 ...
- vue大文件分片上传插件
最近遇见一个需要上传百兆大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现. 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表 ...
- 使用getchar和putchar输入输出单个字符
getchar()和putchar()只能用于输入输出单个字符,而不能字符串. #include<iostream> using namespace std; int main(){ ch ...