最开始学搜索的时候觉得dfs比较简单,现在觉得搜索里面最蛋疼的还是dfs啊。。。bfs说白了就是判个重,写熟了没多困难,A*什么的至少思考的方向比较明确吧(设计估价函数嘛)。。。dfs有各种想不到的神剪枝啊。。。(纯属我这个菜比的个人理解。)
我现在的状态是:能想到的剪枝瞬间就可以想到。。想不到的剪枝不看题解的话怎么也找不到思路。当然一般我想到的剪枝都完全不够啊。。。
还是找了一些dfs题来练习。
第一道题:noi1999 生日蛋糕
题目地址:http://www.wikioi.com/problem/1710/
题目很简洁。思路也应该比较清晰,就是dfs。。。关键看剪枝。(注意除了最大的那层,其它层增加的面积其实就是侧面积。。)
先确定每层枚举r和h的上下界:必然小于上一层(从最大的开始枚举的。。),必然大于等于还要做的层数。
然后想到简单的最值优化一下:如果目前面积已经大于当前最优解了,剪枝。
这样当然远远不够,考虑把那个最值优化加强一下 如果当前面积加上还需填层数的产生的最小面积大于当前最优解的话,剪枝。 至于这个最小面积可以预处理递推出来:考虑第一层r=h=1,第二层r=h=2。。。。
实际测试一下。。。效率依旧很低。。我们来找下原因:前面的剪枝只用到了当前面积与层数两个条件,而当前剩余体积这个重要的制约条件没有考虑进去。。。
于是我们就可以这样设计一下:当前面积+剩下体积产生的最小面积大于当前最优解的话,剪枝。 剩下体积产生的最小面积考虑到形状比较复杂,不好计算出准确值,那我们就可以退一步来想,计算出比这个最小面积更小的一个近似值(如果近似值比最小面积大剪枝就过度了,正确性不能保证)。
至于这个近似值嘛。。。把剩下的层数都当成一层,考虑表示体积的式子为r*r*h,表示面积的式子为2*r*h,那么S=2*V/R,我们带入这里最大可取的R(即比本层r小1),就可算出这个近似的最小S。
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
int n,m;
int V[30+10],S[30+10];//分别是1~n层最少体积和最少面积。
int ans=inf;
void dfs(int pos,int useV,int useS,int lasth,int lastr)
{
if(pos==0)
{
if(useV==n)ans=min(ans,useS);
return;
}
if