DFS:POJ1190-生日蛋糕(基础搜索)

来源:互联网 发布:mac os升级不支持银联 编辑:程序博客网 时间:2024/05/22 20:21

生日蛋糕

Time Limit: 1000MSMemory Limit: 10000KTotal Submissions: 19800Accepted: 7023


描述
7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体。
设从下往上数第i(1 <= i <= M)层蛋糕是半径为Ri, 高度为Hi的圆柱。当i < M时,要求Ri > Ri+1且Hi > Hi+1。
由于要在蛋糕上抹奶油,为尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)的面积Q最小。
令Q = Sπ
请编程对给出的N和M,找出蛋糕的制作方案(适当的Ri和Hi的值),使S最小。
(除Q外,以上所有数据皆为正整数)


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


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


样例输入
100
2


样例输出
68


Hint

圆柱公式
体积V = πR
2H
侧面积A' = 2πRH
底面积A = πR
2


解题心得:

1、之前还以为搜索做的不错了,结果看到这个搜索题就直接蒙了。一开始并没有往搜索这个方向去想,还以为是数学问题,题目的后面还给了遗串公式。后来知道是搜索题的时候还是不太好下手,但是题目给了一个很明确的范围那就是整数范围之内,这样就大大的缩减了范围。


2、就本题来说,它只能深度搜索,遍历每一种情况比较得出最小的面积,它的到最终答案的边界在层数刚好用完于此同时体积也刚好用完。看起来很恐怖,但这道题的精髓就在剪枝,剪枝将这个很恐怖的搜索变得很简单也很快捷。


3、三个剪枝:第一,体积超出或者层数超出可以减去,当前面积大于已经得到的最小面积可以减去。第二,当前剩下的面积加上当前已经得到的面积可以直接减去(在循环中)。第三,剩余层数乘以当前体积小于剩下的体积可以减去(也就是体积用不完了)。三个剪枝之中只有能够想到任意两个都可以过。其实也不是完全想不到,题目给出的条件就体积,层数,面积的限制,剪枝也完全实在这些方面去想,还是完全有可能能够想得到的。


4、做了这个题之后感触很深,其实一些看似完全没有办法的题还是都有迹可循的,就这个题来说,数学方面不可能用公式直接得出答案,也只能够遍历,既然遍历,bfs好像并不是很好弄,那就只能dfs,dfs超时,没办法只能够剪枝,剪枝也只能从面积,体积,层数上面着手,仔细想一下其中的关系,找出相互限制的边界就可以很完美的剪枝。特别是这个题说明了只能是整数,在一个特定的点才能得到答案也是一种做题方向的启示。对题没反应那就只能多做了,做有质量的题,没见过的题才有长进。



#include<stdio.h>int ans = 0;int N,M;void dfs(int m,int left_v,int last_r,int last_h,int sum_s){    if(!left_v && !m)    {        if(ans && sum_s < ans)            ans = sum_s;        else if(ans == 0)            ans = sum_s;        return ;    }    if(m*(last_h-1)*(last_r-1)*(last_r-1) < left_v && m != M)//当前的体积加上未用层数的体积大于给定体积(体积用不完)        return ;    if(m<=0 || left_v<=0 || (sum_s >= ans && ans))//非正常情况        return ;    for(int i=last_r-1;i>=m;i--)    {        for(int j=last_h-1;j>=m;j--)        {            int v = i*i*j;            int s = 2*i*j;            if(m == M)                s += i*i;            if(2*left_v/i + sum_s >= ans && ans)//当前面积和加上剩余的面积大于已经得出的最小面积                continue;            dfs(m-1,left_v-v,i,j,sum_s+s);        }    }}int main(){    scanf("%d%d",&N,&M);    dfs(M,N,100,1000,0);    printf("%d\n",ans);}




原创粉丝点击