深搜:下棋,找路
例如,下棋情况下,一个棋局对应一个点,一个棋局出发走了一步到了另一个棋局,从当前的局面出发,每一条选择都会走到不同的节点,往前,之后要对方有多少走法,之后又要考虑到对方走了这一步,我要怎么走的可能性。
生日蛋糕
题目
Description
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外,以上所有数据皆为正整数)
Input
有两行,第一行为N(N <= 10000),表示待制作的蛋糕的体积为Nπ;第二行为M(M <= 20),表示蛋糕的层数为M。
Output
仅一行,是一个正整数S(若无解则S = 0)。
Sample Input
100
2
Sample Output
68
Hint
圆柱公式
体积V = πR2H
侧面积A' = 2πRH
底面积A = πR2
在搜索题里面往往要提到状态这词。
在图上搜索改变状态的问题
解题思路
深度优先搜索,枚举什么?
枚举每一层可能的高度和半径
如果确定搜索范围?
有限的,最底层的蛋糕的最大可能半径和最大可能高度。
搜索顺序,那些地方体现搜索顺序?
从底层往上搭蛋糕,而不是从顶层往下搭
可行性剪枝:
及早发现我这条路走下去肯定到不了目的地,实现不了我的目标,我就不走了
最优性剪枝:
走到这个地方,我发现及时走到头,能走到目的地,但所花的代价大于我现在求得的最优表面积
可行性剪枝
搭建过程中预见到再往上搭,高度已经无法安排,或者半径已经无法安排,则停止搭建(可行性剪枝)
搭建过程中发现还没打的那些层的体积,一定超过还缺的体积,则停止搭建
搭建过程中发现还没搭的那些层的体积,最大也到不了还缺的体积,则停止搭建
最优性剪枝
搭建过程中发现已建好的面积已超过目前求得的最优表面积,或者预见到搭完后面积一定超过目前最优表面积,则停止搭建。
这里包含一个预见性剪枝
//四个参数觉得了一个状态
搭一个n层的蛋糕,这个蛋糕最底层的半径不能查过r,高度不能超过h,两个状态如何迁移
剩下的任务就是n-1,v-v',r-1,h-1
这是得到了一个新的状态
void Dfs(int v,int n,in r, int h)
//要用n层去凑体积v,最底层半径不能超过r,高度不能超过h
{ //终止条件
if(n==0){
if(v)//v不为0,就失败了
return;
else{minArea=min(minArea,area);return;}
}
if(v<=0)//失败
return ;
for(int rr=r;rr>=n;--rr){//枚举的半径所有可能,枚举到n,因为蛋糕的高度为n,让最高一层的半径为1,所以本层为n
if(n==M)//底面积
area=rr*rr;//每一层蛋糕的面积投影到最底层,面积的初始值
for(int hh=h;hh>=n;--hh){//高度的变化
area+=2*rr*hh;//表面积,算侧面积,周长成绩高,正在搭的蛋糕的面积增加了
Dfs(v-rr*rr*hh,n-1,rr-1,hh-1);//之后再进行递归,尝试别的rr的组合
area-=2*rr*hh;//要恢复为原来的样子,要减去
}
}
}
int N,M;
int minArea=1<<30;//最优表面积
int area=0;//正在搭建中的蛋糕的表面积
int main(){
````
Dfs(N,M,maxR,maxH);
//我要搭一个N个蛋刀,高度为M,最大半径,最大体积,这就是所谓的初始状态
if(minArea==1<<30)
cout<<0<<end1;//搭不了蛋糕
else
cout<<minArea<<end1;
}
来源:CSDN
作者:weixin_44522477
链接:https://blog.csdn.net/weixin_44522477/article/details/104891838