搜索的优化1——剪枝
何谓剪枝?我们可知,搜索是基于搜索树的一个算法,所谓剪枝,就如其字面的意思,剪去一些没有用的枝条。
显然这样可以加快搜索的进程,从而减小时间复杂度。
剪纸的原则:1,正确——不能剪掉含有我们需要的解的枝条,2,准确,3,高效
一些常用的剪纸方法:
1,可行性剪枝(上下界剪枝)
搜索是一种暴力的算法,其思想是有n层,再每层进行枚举等操作,在到达边界条件的时候,判断找到的解是否合法。
通过这个思想我们可以枚举的范围,确定下界和上界,从而达到剪枝的目的。其中确定上界是因为,如果超过枚举上界
往往就不能抵达递归边界了,所以成为可行性剪枝。
例题[NOIP提高组]数的划分
Description
将整数N分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序),问有多少种方案数。
例如 将整数7分成3份,我们认为1 1 5; 1 5 1; 5 1 1是同一种分法。
Input
第一行两个整数N和M
Output
一行代表总的方案数
首先只考虑单纯搜索的做法,只是有K层,每层枚举一个数满足a1+a2+...+ak=n即可,方案数不得冲突。
因为每一层存在枚举一个数字,所以考虑上下界剪枝,我们可以发现因为要求方案不相同,所以ai<=ai+1
所以我们确定了枚举的下界ai-1,再考虑枚举的上界,因为要求分成k份,要求k份的总和为n,所以假设我们
现在枚举到了第pos个数,前pos-1个数的和为sum,为了既满足ai-1<=ai并且k份的总和能够达到n,所以剩下
每一位的大小不能超过(n-sum)/(k-pos),所以只要满足sum+i*(k-pos)<=n即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #define maxn 10 6 7 using namespace std; 8 9 int n,k; 10 int ans; 11 12 inline void dfs(int pre,int sum,int pos) 13 { 14 if(pos==k) 15 { 16 if(sum==n) ans++; 17 return; 18 } 19 for(register int i=pre;sum+i*(k-pos)<=n;++i) 20 dfs(i,sum+i,pos+1); 21 } 22 23 int main() 24 { 25 scanf("%d%d",&n,&k); 26 dfs(1,0,0); 27 printf("%d ",ans); 28 return 0; 29 }
2,记忆话搜索
所谓记忆话,就是对于所有已经搜到的节点进行记忆话,这样可以避免子问题被重复计算,从而完成剪枝。
例题[SHOI2002]滑雪
Description
Michael喜欢滑雪。这并不奇怪,因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当
你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael想知道在一个区域中最长的滑坡。区域由一
个二维数组给出。数组的每个数字代表点的高度。下面是一个例子:
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可行的滑坡为
24-17-16-1(从24开始,在1结束)。当然25-24-23-...-3-2-1更长。事实上,这是最长的一条。
Input
输入的第一行为表示区域的二维数组的行数R和列数C(1≤R,C≤100)。下面是R行,每行有C个数,代表高度
(两个数字之间用1个空格间隔)。
Output
输出区域中最长滑坡的长度。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 5 using namespace std; 6 7 int dx[4]={0,-1,0,1}; 8 int dy[4]={-1,0,1,0}; 9 int f[110][110],g[110][110]; 10 int r,c,ans; 11 12 inline int dfs(int x,int y) 13 { 14 int nx,ny,t; 15 if(f[x][y]!=0) return f[x][y]; 16 t=1; 17 for(int i=0;i<4;i++) 18 { 19 nx=x+dx[i];ny=y+dy[i]; 20 if(nx>=1&&nx<=r&&ny>=1&&ny<=c&&g[nx][ny]>g[x][y]) 21 { 22 int tmp=dfs(nx,ny)+1; 23 if(tmp>t) t=tmp; 24 } 25 } 26 f[x][y]=t; 27 return t; 28 } 29 30 int main() 31 { 32 int t; 33 scanf("%d%d",&r,&c); 34 for(int i=1;i<=r;i++) 35 for(int j=1;j<=c;j++) 36 scanf("%d",&g[i][j]); 37 memset(f,0,sizeof(f)); 38 for(int i=1;i<=r;i++) 39 for(int j=1;j<=c;j++) 40 { 41 t=dfs(i,j); 42 f[i][j]=t; 43 if(t>ans) ans=t; 44 } 45 printf("%d",ans); 46 return 0; 47 }