当前位置: 首页 > news >正文

(DFS + 剪枝)【洛谷P1731】 [NOI1999] 生日蛋糕

题目链接

点此快速前往

题目总分析

就和我说的一样,这道题就是DFS加剪枝,非常好的一道题

我起初看到这个题我根本不知道怎么dfs才是正确的, 感觉变量有这么多不确定的,每一层的半径,每一层的高度,而且这之间的联系在刚看到这个题的我看来十分的小,应该是我太菜了导致的

深入往下看,你就发现实际上这道题已经告诉了你每一层的限制了,并不是完全无从下手,至少你知道这一层的半径和高度一定小于等于它底下那一层的半径和高度-1,所以我们不难想象出dfs的做法:最下面那一层的半径最大值是假设只有一层,n-1就是它起初的最大值,那么最小值就是总共的层数,,因为每一层都要至少要少1,所以最大的那一层半径和高度肯定就最小值就是层数

为什么不遍历高度而是半径呢?

你稍微列一下式子你就会发现,实际上半径对总面积的影响程度要高于高度的,所以想要最小,一定是从半径入手。

总体积 n = ∑ i = 1 m R i ∗ H i 总体积 n = \sum_{i = 1}^{m} R_i * H_i 总体积n=i=1mRiHi

总面积 m = R 0 2 + ∑ i = 1 m R i 2 ∗ H i 总面积 m = R_0^2 + \sum_{i=1}^{m} R_i^2 * H_i 总面积m=R02+i=1mRi2Hi

为什么总面积前面有个 R 0 2 R_0^2 R02

简单想想,虽然是每个圆柱都被另一个比它小的圆柱盖住了一个圆的面积,但是你从这个蛋糕的最上面去看,就不难发现,最上面的面积和其实就是最底层圆柱的顶面面积。

看到这可能已经想要去写了,不过先停一下
这道题dfs搜索只是第一步,而更重要的是剪枝,由于处理数据的量也是非常大的,如果不进行一些优化就没办法顺利进行

首先既然我们知道每一层最小的半径和高,那么我们就不难算出来到每一层为止,最小的体积和最小的面积分别是多少

有了上述的信息之后,我们在准备遍历之前可以先判断一下

  1. 如果此时此刻接下来几层的最小面积加上此时的面积已经大于等于当前的最优解你,那就没有必要去遍历了。
  2. 同样,接下里几层的最小体积加上此时的体积已经大于要求的总体积n,那么也没必要去遍历了
  3. 这个是比较难想的,我们是从最下层遍历到最上层的,也就是说假设此时此刻遍历的层数半径为r,包括这一层之前的总体积为v以及总面积是s , 总共的蛋糕体积是n,那么如果 2 ∗ ( n − v ) / r > 此时的最优解 2 * (n - v) / r > 此时的最优解 2(nv)/r>此时的最优解,同样也没有遍历下去的必要了

前两个好理解,第三个是什么东西啊?
很好我开始看到的时候也非常困惑,接下来推导一下你就懂了

从m开始now是已经搭建好的层数了,now-1就是接下来之后的层

接下里的面积应该是 ∑ i = 1 n o w − 1 R i 2 ∗ H i 接下里的面积应该是\sum_{i = 1}^{now - 1} R_i^2 * H_i 接下里的面积应该是i=1now1Ri2Hi
看一下我第三条公式,你可以清楚的发现, R i R_i Ri全部都小于当前这一层的 r 所以,接下里的面积必然比 2 ∗ ( n − v ) / r 2 * (n - v) / r 2(nv)/r大,如果这个面积都大于等于最优解了,那么就不需要遍历了

接下来就是代码实现了,基本思路已经写完,代码中有不理解的部分可以评论区提问一下或者私信。

总代码

#include<bits/stdc++.h>
using namespace std;
const int N = 25 , INF = 0x3f3f3f3f;
int n,m;
int ans = INF;
int Mins[N] , Minv[N];
void dfs(int now,int r,int h,int s,int v)
{int MH = h;if(now == 0){if(v == n){ans = min(ans, s);}return ;}if(Mins[now-1] + s >= ans) return;if(Minv[now-1] + v > n) return;if(2 * (n - v) / r + s >= ans) return;for(int i=r-1;i>=now;i--){if(now == m) s = i * i;MH = min(h-1 , (n - Minv[now-1] - v) / i / i);for(int j = MH ; j >= now ; j--){dfs(now-1 , i , j , s + 2 * i * j , v + i * i * j);}}
}int main()
{cin >> n >> m;for(int i=1;i<=m;i++){Mins[i] = Mins[i-1] + i * i * 2;Minv[i] = Minv[i-1] + i * i * i;}dfs(m,n,n,0,0);if(ans == INF) cout << 0 << '\n';else cout << ans << '\n';return 0;
}

相关文章:

  • 章节10实验--Ubuntu18.04 Qt MySQL libqsqlmysql.so
  • QT信号和槽机制connect用法
  • Centos上安装Harbor并使用
  • 樊登读书-《终生成长》【视频笔记 +个人思考】
  • MR混合现实情景实训教学实验系统能帮助解决石油化工专业当前哪些教学困境
  • css实现的3D立体视觉效果鸡蛋动画特效
  • 【隐私计算实训营——004上手隐语SecretFlow和SecretNote安装部署】
  • 邮箱的正则表达式
  • 如何安装Jenkins指定版本
  • 【Springboot3+Mybatis】文件上传阿里云OSS 基础管理系统CRUD
  • draw.io 去除箭头
  • 【黄金手指】windows操作系统环境下使用jar命令行解压和打包Springboot项目jar包
  • Javascript中的严格模式 “use strict“
  • 华为ensp中rip动态路由协议原理及配置命令(详解)
  • 29-5 webshell 流量分析 - 菜刀
  • 网络传输文件的问题
  • 0x05 Python数据分析,Anaconda八斩刀
  • JS变量作用域
  • js递归,无限分级树形折叠菜单
  • Koa2 之文件上传下载
  • PV统计优化设计
  • Python利用正则抓取网页内容保存到本地
  • SSH 免密登录
  • Windows Containers 大冒险: 容器网络
  • 大数据与云计算学习:数据分析(二)
  • 对超线程几个不同角度的解释
  • 给Prometheus造假数据的方法
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • 前端存储 - localStorage
  • 前端面试总结(at, md)
  • 让你的分享飞起来——极光推出社会化分享组件
  • 如何实现 font-size 的响应式
  • 微信小程序填坑清单
  • #stm32整理(一)flash读写
  • ()、[]、{}、(())、[[]]等各种括号的使用
  • (13)Hive调优——动态分区导致的小文件问题
  • (4)logging(日志模块)
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • (源码版)2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模
  • (转载)CentOS查看系统信息|CentOS查看命令
  • (转载)OpenStack Hacker养成指南
  • .Net core 6.0 升8.0
  • .net 托管代码与非托管代码
  • .NET关于 跳过SSL中遇到的问题
  • /etc/sudoer文件配置简析
  • [ IOS ] iOS-控制器View的创建和生命周期
  • [20190113]四校联考
  • [Android学习笔记]ScrollView的使用
  • [CQOI 2010]扑克牌
  • [DM复习]关联规则挖掘(下)
  • [Gamma]阶段测试报告
  • [HTML]HTML5实现可编辑表格
  • [IOI2018] werewolf 狼人