搜索 算法(二)

一.搜索算法的处理技巧

1.与回溯法结合

  在 搜索算法中,我们简单了解了DFS与BFS的基本概念和基本模板。
  在处理搜索问题时,我们会遇到这种情况,当前结点无法向纵深方向拓展,而题干要求我们搜索全部的解,此时我们就可以往回移动至最近的结点,以此结点拓展出其他的子结点,以找到新的解。这个操作过程就运用了回溯法。

  回溯法提高解决问题的效率,经常与深度优先搜索结合使用。为了方便理解,下面给出一个例题来体现回溯法怎样优化我们的搜索过程。

题目:

任何一个大于1的自然数 n ,总可以拆分成若干个小于 n 的自然数自然数之和。

分析:
  分析题目得,我们可以用DFS来搜索所有成立的和式。那么我们可以用一个数组的 a[ i ] 来存放一个解中第 i 层的子结点。
在这里插入图片描述
  在本题中不要求顺序,我们将1+1+2与1+2+1看作一个和式。那么我们经历1->1->1->1后,该如何走1->1->2的解呢?这里就可以结合回溯法了。
在这里插入图片描述
  总结来说,回溯可以理解为返回上一层的状态,即恢复现场;在本题中就体现为 s-=i 进入下一层结点,而回溯的操作就是 s+=i (返回上一层结点)。

代码:

#include<cstdio>
#include<iostream>
#include<cstdlib>
using namespace std;
int a[10001]={1},n,total;
void search(int,int);
void print(int);
int main()
{  cin>>n;
   search(n,1);                   //将要拆分的数n传递给s
   cout<<"total="<<total<<endl;  //输出拆分的方案数
}
void print(int t)
{  cout<<n<<"=";
   for (int i=1;i<=t-1;i++)
   cout<<a[i]<<"+";
   cout<<a[t]<<endl;
   total++;
}
void search(int s,int t)
{  int i;
   for (i=a[t-1];i<=s;i++)
   if (i<n)
 { a[t]=i;//保存当前拆分的数i
   s-=i; //s减去数i, s的值将继续拆分
   if (s==0) print(t);
   else search(s,t+1);
   s+=i; //回溯:加上拆分的数,以便产分所有可能的拆分
 }
}

2.与剪枝法法结合

  剪枝,可以理解为剪去搜索树中的某些“枝条”(即结点及其扩展的其他结点)。通过判断枝条有无用处,剪去无用的枝条,就可以避免一些不必要的遍历过程。

剪枝法与搜索算法的结合主要体现在两方面:
1.用约束函数在扩展结点处剪除不满足约束条件的路径;
2.用限界函数剪去得不到问题的解或最优解的路径。

小明参加一个抢东西的电视节目。这个节目很有意思,一共有n个东西可以拿(n<50)每个参加活动的人不能拿重量超过m(m<2000)的东西,而每个东西都有它的价值v,有的高有的低,帮助小明安排要拿的东西,使总价值最高。

在这里插入图片描述

二、题型整理

  • 棋盘问题:N皇后,解数独等。

例题链接P1219 [USACO1.5]八皇后 Checker Challenge.

题意:在n*n的棋盘上放棋子,要求所有的棋子不在同一行,同一列和同一对角线上,问有多少种放法,并输出前三种情况。

题解
1.用三个数组分别表示列、左下到右上的对角线,左上到右下的对角线的状态。
2.用深搜遍历棋盘,若合法则填入,同时标记这个空,再进行下一层递归,否则取消标记进行回溯。

  • 组合问题:N个数里面按一定规则找出k个数的集合。

例题链接: P1036 [NOIP2002 普及组] 选数

题意:n个数中任选k个数相加求和(k<n),求所有组合中和为素数的有几种。

题解
1.DFS遍历所有组合,用函数判断是否为素数,设total记录合法结果的个数。
2.一个最多20个数,每一次循环为1或0的循环,即表示这个数是否被选择。
3.元素满足三个的时候,用return来结束。

  • 排列问题:N个数按一定规则全排列,有几种排列方式

时间问题先总结到这,后续会继续补充。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值