P1731 [NOI1999] 生日蛋糕——典型的回溯和剪枝题目,值得一看

本文主要是介绍P1731 [NOI1999] 生日蛋糕——典型的回溯和剪枝题目,值得一看,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天尝试了一下md的编辑器,不知道有没有什么改变

[NOI1999] 生日蛋糕

题目背景

数据加强版 link

题目描述

7 月 17 日是 Mr.W 的生日,ACM-THU 为此要制作一个体积为 N π N\pi Nπ M M M 层生日蛋糕,每层都是一个圆柱体。

设从下往上数第 i i i 1 ≤ i ≤ M 1 \leq i \leq M 1iM)层蛋糕是半径为 R i R_i Ri,高度为 H i H_i Hi 的圆柱。当 i < M i \lt M i<M 时,要求 R i > R i + 1 R_i \gt R_{i+1} Ri>Ri+1 H i > H i + 1 H_i \gt H_{i+1} Hi>Hi+1

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

请编程对给出的 N N N M M M,找出蛋糕的制作方案(适当的 R i R_i Ri H i H_i Hi 的值),使 S = Q π S=\dfrac{Q}{\pi} S=πQ 最小。

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

输入格式

第一行为一个整数 N N N N ≤ 2 × 1 0 4 N \leq 2 \times 10^4 N2×104),表示待制作的蛋糕的体积为 N π N\pi Nπ

第二行为 M M M M ≤ 15 M \leq 15 M15),表示蛋糕的层数为 M M M

输出格式

输出一个整数 S S S,若无解,输出 0 0 0

样例 #1

样例输入 #1

100
2

样例输出 #1

68

这个题是一道显然的回溯加剪枝的题目,首先我们要把基础的方法写出来,再来剪枝。所以我们很轻松就可以想到这样的解法:
1.枚举层数(从n到1),半径,高度,体积以及面积,在层数达到0并且体积恰好等于n的时候将面积与面积的最小值进行比较,如果比他小就更改。
2.在函数内部枚举半径i和高度h,范围题目已经告诉你了。
3.当已选中一个高度和一个半径的时候,就按照题目的要求进行下一次的递归。
也就是这样

#include<bits/stdc++.h>
using namespace std;int n,m,minn=INT_MAX;void dfs(int step,int r,int h,int s,int v){if (step==0&&v==n){minn=min(s,minn);return;}for (int i=r-1;i>=step;i--){if (step==m)s=i*i;//这个地方很重要,一定要记得将下表面存着for (int j=h-1;j>=step;j--){dfs(step-1,i,j,s+2*i*j,v+i*i*j);}}return;
}
int main(){cin>>n>>m;dfs(m,n,n,0,0);if (minn==INT_MAX)cout<<0;else cout<<minn;return 0;
}

接下来就是肯定是剪枝了,怎么剪呢?很容易就可以想到如果当前的面积加上往后最小的面积和都要比最小的面积情况大的话,直接退出,同样又有如果当前的v已经大于了n也是直接退出,再有如果当前的v从而算出来的s也是大于最小的面积的话,也是直接退出。代码如下:

#include<bits/stdc++.h>
using namespace std;int n,m,minn=INT_MAX;
int mins[30000],minv[30000];void dfs(int step,int r,int h,int s,int v){if (step==0){if (v==n)minn=min(s,minn);return;}if (s+mins[step-1]>=minn)return;if (v+minv[step-1]>n)return;if(2.0*(n-v)/r+s>=minn)  return;//要用小数,不能用整数,要不然要出错for (int i=r-1;i>=step;i--){if (step==m)s=i*i;for (int j=h-1;j>=step;j--){dfs(step-1,i,j,s+2*i*j,v+i*i*j);}}return;
}
int main(){cin>>n>>m;for (int i=1;i<=m;i++){mins[i]=mins[i-1]+2*i*i;//记录面积的最小minv[i]=i*i*i;//记录体积的最小}dfs(m,n,n,0,0);if (minn==INT_MAX)cout<<0;else cout<<minn;return 0;
}

那么到了这里,基本上函数根本上的优化是没有了,这时候我们就要考虑一下优化循环了:
半径肯定是不能优化了,那么我们就要考虑一下高度了,能不能优化呢?显然是可以的,我们可以用总的体积减去当前的体积和后面最小的体积和再来除以i²得到后面的h并与当前的h进行比较,从而缩短循环的时间,代码如下:

#include<bits/stdc++.h>
using namespace std;int n,m,minn=INT_MAX;
int mins[30000],minv[30000];void dfs(int step,int r,int h,int s,int v){int maxh=h;if (step==0){if (v==n)minn=min(s,minn);return;}if (s+mins[step-1]>=minn)return;if (v+minv[step-1]>n)return;if(2.0*(n-v)/r+s>=minn)  return;for (int i=r-1;i>=step;i--){if (step==m)s=i*i;maxh=min(h-1,(n-minv[step-1]-v)/i/i);for (int j=maxh;j>=step;j--){dfs(step-1,i,j,s+2*i*j,v+i*i*j);}}return;
}
int main(){cin>>n>>m;for (int i=1;i<=m;i++){mins[i]=mins[i-1]+2*i*i;minv[i]=i*i*i;}dfs(m,n,n,0,0);if (minn==INT_MAX)cout<<0;else cout<<minn;return 0;
}


看了这么久,作者也写了这么久,能不能点一个赞,在收藏一下呢?最好的话在点个关注吧

谢谢啦!​
在这里插入图片描述

这篇关于P1731 [NOI1999] 生日蛋糕——典型的回溯和剪枝题目,值得一看的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/889242

相关文章

poj2505(典型博弈)

题意:n = 1,输入一个k,每一次n可以乘以[2,9]中的任何一个数字,两个玩家轮流操作,谁先使得n >= k就胜出 这道题目感觉还不错,自己做了好久都没做出来,然后看了解题才理解的。 解题思路:能进入必败态的状态时必胜态,只能到达胜态的状态为必败态,当n >= K是必败态,[ceil(k/9.0),k-1]是必胜态, [ceil(ceil(k/9.0)/2.0),ceil(k/9.

usaco 1.3 Prime Cryptarithm(简单哈希表暴搜剪枝)

思路: 1. 用一个 hash[ ] 数组存放输入的数字,令 hash[ tmp ]=1 。 2. 一个自定义函数 check( ) ,检查各位是否为输入的数字。 3. 暴搜。第一行数从 100到999,第二行数从 10到99。 4. 剪枝。 代码: /*ID: who jayLANG: C++TASK: crypt1*/#include<stdio.h>bool h

题目1254:N皇后问题

题目1254:N皇后问题 时间限制:1 秒 内存限制:128 兆 特殊判题:否 题目描述: N皇后问题,即在N*N的方格棋盘内放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在同一斜线上。因为皇后可以直走,横走和斜走如下图)。 你的任务是,对于给定的N,求出有多少种合法的放置方法。输出N皇后问题所有不同的摆放情况个数。 输入

题目1380:lucky number

题目1380:lucky number 时间限制:3 秒 内存限制:3 兆 特殊判题:否 提交:2839 解决:300 题目描述: 每个人有自己的lucky number,小A也一样。不过他的lucky number定义不一样。他认为一个序列中某些数出现的次数为n的话,都是他的lucky number。但是,现在这个序列很大,他无法快速找到所有lucky number。既然

hdu1010 奇偶剪枝

恰好t时间到达 import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWriter;import java.math.BigInteger;import java.util.Arrays;import

【408数据结构】散列 (哈希)知识点集合复习考点题目

苏泽  “弃工从研”的路上很孤独,于是我记下了些许笔记相伴,希望能够帮助到大家    知识点 1. 散列查找 散列查找是一种高效的查找方法,它通过散列函数将关键字映射到数组的一个位置,从而实现快速查找。这种方法的时间复杂度平均为(

回溯——9.全排列

力扣题目链接 给定一个 没有重复 数字的序列,返回其所有可能的全排列。 示例: 输入: [1,2,3]输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] 解题思路 问题建模:题目要求给出一个数组的所有排列组合,属于典型的全排列问题,这可以用回溯法来解决。回溯法通过递归的方式,依次将数组中的每个元素放入排列中,直到生成

码蹄集部分题目(2024OJ赛9.4-9.8;线段树+树状数组)

1🐋🐋配对最小值(王者;树状数组) 时间限制:1秒 占用内存:64M 🐟题目思路 MT3065 配对最小值_哔哩哔哩_bilibili 🐟代码 #include<bits/stdc++.h> using namespace std;const int N=1e5+7;int a[N],b[N],c[N],n,q;struct QUERY{int l,r,id;}que

深度剖析AI情感陪伴类产品及典型应用 Character.ai

前段时间AI圈内C.AI的受够风波可谓是让大家都丈二摸不着头脑,连C.AI这种行业top应用都要找谋生方法了!投资人摸不着头脑,用户们更摸不着头脑。在这之前断断续续玩了一下这款产品,这次也是乘着这个风波,除了了解一下为什么这么厉害的创始人 Noam Shazeer 也要另寻他路,以及产品本身的发展阶段和情况! 什么是Character.ai? Character.ai官网:https://

2024 年高教社杯全国大学生数学建模竞赛题目——2024 年高教社杯全国大学生数学建模竞赛题目的求解

2024 年高教社杯全国大学生数学建模竞赛题目 (请先阅读“ 全国大学生数学建模竞赛论文格式规范 ”) 2024 年高教社杯全国大学生数学建模竞赛题目 随着城市化进程的加快、机动车的快速普及, 以及人们活动范围的不断扩大,城市道 路交通拥堵问题日渐严重,即使在一些非中心城市,道路交通拥堵问题也成为影响地方经 济发展和百姓幸福感的一个“痛点”,是相关部门的棘手难题之一。 考虑一个拥有知名景区