1.当前搜到的东西劣于答案,或者当前搜到的加上之后能取到最最最优的(估价)依然劣于答案,return
2.对于第1点可以在搜前先估一个答案上界
3.按一定顺序枚举,如从小到大或从大到小,减少相同状态
4.对第3点,在一大部分题里从大到小枚更好,因为能更快得到一个答案用于剪掉后面的
5.每层枚举时可判掉一些无用状态
例题:
1.洛谷P1731 [NOI1999]生日蛋糕
链接:https://www.luogu.org/problemnew/show/P1731
// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
int n,m,r[20],h[20],ans=2e9;
int sigma(int x)
{return x*(x+1)*(2*x+1)/6;}
int S(int r,int h)
{return 2*r*h;}
void dfs(int pos,int las,int res)
{
if(res+sigma(m-pos+1)>ans)return;
if(pos!=1&&las-(m-pos+1)*r[pos-1]*r[pos-1]*h[pos-1]>0)return;
if(las<=0)return;
int mnr,mxr,mnh,mxh,tp;
mxr=min(las,r[pos-1]-1);
mnr=max(m-pos+1,(int)sqrt(las/(h[pos-1]-1)/(m-pos+1)));
for(int i=mxr;i>=mnr;i--)
{
r[pos]=i;tp=i*i;
if(pos==m)
{
h[pos]=las/tp;
if(h[pos]<h[pos-1]&&h[pos]*i*i==las)
ans=min(ans,res+S(i,h[pos])+((pos==1)?tp:0));
}
else
{
mxh=min(h[pos-1]-1,(las-sigma(m-pos))/tp);
mnh=m-pos+1;
for(int j=mxh;j>=mnh;j--)
{
h[pos]=j;
dfs(pos+1,las-tp*j,res+S(i,j)+((pos==1)?tp:0));
}
}
}
}
int main()
{
cin>>n>>m;
r[0]=h[0]=1e9;
dfs(1,n,0);
ans==2e9?puts("0"):printf("%d\n",ans);
}
2.ZJOI2005 最少乘法次数
#pragma GCC optimize(3,"inline","Ofast")
#define ll unsigned long long
#include<bits/stdc++.h>
using namespace std;
int n,ans=0;
bool vis[2010];
int a[30],mo[20];
void init()
{
int tp=n,cnt=0;
while(tp)ans++,tp-=tp&-tp;tp=1;
if(ans)ans--;
while(tp<=n)cnt++,tp<<=1;
ans+=cnt-1;
ans=min(ans,(int)(4*floor(log2(n))/3+2));
ans=min(ans,14);
}
void dfs(int pos,int mx)
{
ll x=0,y=0;
if(pos>=ans)return;
if(mx*mo[ans-pos]<n)return;
for(int i=1;i<=pos;i++)
for(int j=i;j<=pos;j++)
if(a[i]+a[j]==n){ans=min(ans,pos);return;}
for(int i=pos;i>=1;i--)
for(int j=i;j>=1;j--)
if(a[i]+a[j]<n&&!vis[a[i]+a[j]])
{
vis[a[i]+a[j]]=1;
a[pos+1]=a[i]+a[j];
if(a[pos+1]>mx)
dfs(pos+1,a[pos+1]);
vis[a[i]+a[j]]=0;
}
return;
}
int main()
{
scanf("%d",&n);
//freopen("ot.txt","w",stdout);
init();mo[0]=1;
for(int i=1;i<=15;i++)mo[i]=mo[i-1]*2;
a[1]=1,vis[1]=1,dfs(1,1);
cout<<ans;
}