IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 2021.8.6 [NOI1999] 生日蛋糕:一道剪枝复杂的深搜 -> 正文阅读

[数据结构与算法]2021.8.6 [NOI1999] 生日蛋糕:一道剪枝复杂的深搜

题目:P1731 [NOI1999] 生日蛋糕 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

这是一道深搜剪枝的好题。为什么好呢?..

因为我调试的快吐了,好多剪枝条件,一直没有想到...头秃= =

以前没有遇到过这么多剪枝条件的题目...

刚开始这道题开住我,因为这道题与一般的深搜题不一样,没有什么明显的选择条件。仔细读题,要求R、H递增,那么R、H的边界条件我们就可以找出,两个for循环列出R、H的枚举,每次枚举的R、H进入下一层搜索。这是本题与一般深搜题相比不同寻常的一点。

for (int R = r-1; R >= m; R--)//枚举这一层的半径
	{			
		if (m == M)//处理最底层蛋糕的上表面
				area = R * R;
		int Hmax = min(int((rest - MinV[m - 1]) / (R * R)),h-1);//相当于对H剪枝
		for (int H = Hmax; H >= m; H--)//枚举这一层的高度
		{
			//cout << "r=" << R << "h=" << H << "area=" << area + 2 * R * H << "rest=" << rest - R * R * H << "m=" << m << endl;//测试
			dfs(R, H, area + 2 * R * H, rest - R * R * H, m - 1);//进入下一层
		}
	}

对下面代码中剪枝条件3:一个关键推理进行说明。(太懒了,手写的将就着看吧,反正只有我自己看)

#include<bits/stdc++.h>
using namespace std;
int N, M, ans = 1e9;
int MinS[20], MinV[20];
void dfs(int r, int h, int area, int rest, int m)//r当前层数半径 h当前层数高 area当前层数表面积 rest当前层数剩余可用体积 m当前层数(可以理解为初到当前层)
{
	if (m == 0 && rest == 0)
	{
		ans = min(ans, area);//标准深搜最小值
		return;
	}
	/**玛德下面把m写成M一下午没有找出来错误!!!气死我了!!!**/
	if (area + MinS[m - 1] >= ans) return;//剪枝条件1:当前表面积 + 剩余最小表面积之和应该 < ans
	if (rest < MinV[m - 1] || m <= 0)return;//剪枝条件2:剩余可用体积应该 >= 剩下最小体积
	if (area + 2 * rest / r >= ans) return;//剪枝条件3:一个关键推理
	int Rmax = min(int(pow(rest - MinV[m - 1], 0.5)),r-1);//假设H==1,取R的最大值,相当于对R剪枝
	for (int R = r-1; R >= m; R--)//枚举这一层的半径
	{			
		if (m == M)//处理最底层蛋糕的上表面
				area = R * R;
		int Hmax = min(int((rest - MinV[m - 1]) / (R * R)),h-1);//相当于对H剪枝
		for (int H = Hmax; H >= m; H--)//枚举这一层的高度
		{
			//cout << "r=" << R << "h=" << H << "area=" << area + 2 * R * H << "rest=" << rest - R * R * H << "m=" << m << endl;//测试
			dfs(R, H, area + 2 * R * H, rest - R * R * H, m - 1);//进入下一层
		}
	}
}
int main(void)
{
	int sum = 0;
	cin >> N >> M;//N为蛋糕体积,M为蛋糕层数
	for (int i = M; i >= 1; i--)
	{
		sum += i * i * i;
	}
	if (sum > N)
	{
		cout << 0;//先将无解的情况排除
		return 0;
	}
	for (int i = 1; i <= M; i++)
	{
		MinV[i] = MinV[i - 1] + i * i * i;//从上往下数,前i层最小体积之和
		MinS[i] = MinS[i - 1] + 2 * i * i;//从上往下数,前i层最小表面积之和
	}
	dfs(N, N, 0, N, M);
	if (ans < 1e9)
	{
		cout << ans;
	}
	else
		cout << 0;
	return 0;
}

这道题花了我好长好长时间。我太菜了呀...

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-07 12:20:33  更:2021-08-07 12:22:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 2:05:32-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计