深搜

按照一定的顺序和规则,一直往深处走,直到走不通再返回,换一种路径重复上述步骤。
深搜一般可以找到问题的所有答案,但问题规模较大时,解集树的深度就会比较大并且比较宽,时间复杂度就会较高。与广搜相比,深搜的空间复杂度会较低,因为深搜是深度优先,只需要存储当前子树的状态,不需要像广搜那样存储大量状态。

优化

1、可行性剪枝和最优性剪枝
2、记忆化搜索
3、减少重复搜索

问题练习

P1451 求细胞数量
深搜的入门题,求出连通块,把搜索过的地方做标记,记录连通块数量即可

#include <bits/stdc++.h>
#define eps 1e-15
using namespace std;
int n,m,a[105][105],r[4]={-1,1,0,0},c[4]={0,0,-1,1};
void dfs(int i, int j){a[i][j]=0;for(int k=0; k<4; k++){int b=i+r[k],d=j+c[k];if(a[b][d] != 0 && 1<=b && b<=n && d>=1 && d<=m)dfs(b,d);}
}int main()
{cin>>n>>m;for(int i=1; i<=n; i++)for(int j=1; j<=m; j++)scanf("%1d",&a[i][j]);int ans=0;for(int i=1; i<=n; i++)for(int j=1; j<=m; j++){if(a[i][j]!=0)dfs(i,j),ans++;}cout<<ans;return 0;
}

P1162 填涂颜色
也是求连通块的题,如果找圈内的块,不知道具体在哪,不好去控制深搜程序。如果找出圈外的连通块,把圈外的涂色,就能区别出圈内的。

#include <bits/stdc++.h>
#define eps 1e-15
using namespace std;
int n,a[35][35],b[35][35],x[4]={-1,1,0,0},y[4]={0,0,-1,1};
void dfs(int r, int c){if(b[r][c]==1 || b[r][c]==2)return;b[r][c]=2;for(int k=0; k<4; k++){int rr=r+x[k],cc=c+y[k];if(rr>=1 && rr<=n && cc>=1 && cc<=n)dfs(rr,cc);}
}
/*
6
1 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1
*/
int main()
{cin>>n;for(int i=1 ;i<=n; i++)for(int j=1; j<=n; j++){cin>>a[i][j];b[i][j]=a[i][j];}//这样能保证找出圈外的所有连通块for(int i=1; i<=n; i++)dfs(1,i);for(int i=1; i<=n; i++)dfs(i,1);for(int i=1; i<=n; i++)dfs(n,i);for(int i=1; i<=n; i++)dfs(i,n);for(int i=1; i<=n; i++){for(int j=1; j<=n; j++)if(1==b[i][j])cout<<1<<" ";else if(b[i][j]==2)cout<<0<<" ";else if(b[i][j]==0)cout<<2<<" ";cout<<endl;}return 0;
}

P1141 01迷宫
还是连通块的题,但是技巧巧妙。
每次搜索都能找出一个连通块,连通块内能到达的数量都是一样的。
flag数组用来存答案数组的下标,ans数组用来存答案。
还需要注意搜索完后恢复a数组的状态。不能在每一层深搜结束后把当前的答案直接当成这个点的最终答案,因为这样不能保证这个连通块的每个值都是相同的。

#include <bits/stdc++.h>
#define eps 1e-15
using namespace std;
int n,a[1005][1005],flag[1005][1005],r[4]={-1,1,0,0},c[4]={0,0,-1,1},ans[1000005];
void dfs(int i, int j,int l){if(!flag[i][j]){ans[l]++;flag[i][j]=l;}int x=a[i][j];a[i][j]=-1;for(int k=0; k<4; k++){int b=i+r[k], d=j+c[k];if(b>=1 && b<=n && d>=1 && d<=n && a[b][d]+x == 1 && flag[b][d])continue;if(b>=1 && b<=n && d>=1 && d<=n && a[b][d]+x == 1 )dfs(b,d,l);}a[i][j]=x;
}
int main()
{int m,k=1;cin>>n>>m;for(int i=1; i<=n; i++)for(int j=1; j<=n; j++)scanf("%1d",&a[i][j]);while(k<=m){int in1,in2;scanf("%d%d",&in1,&in2);if(flag[in1][in2]!=0)cout<<ans[flag[in1][in2]];else dfs(in1,in2,k),cout<<ans[flag[in1][in2]];k++;if(k<=m)cout<<endl;}return 0;
}

P1036 [NOIP2002 普及组] 选数
和全排列写法有些许类似,感觉比全排列问题简单

#include <bits/stdc++.h>
#define eps 1e-15
using namespace std;
int n,k,a[25],sum,ans;
bool judge(int i){bool f=true;for(int j=2; j<=i/2; j++){if(i%j==0){f=false;break;}}return f;
}
void dfs(int ne, int i){if(i>k){if(judge(sum))ans++;return;}for(int j=ne; j<=n-k+i; j++)sum+=a[j],dfs(j+1,i+1),sum-=a[j];
}
int main()
{cin>>n>>k;for(int i=1; i<=n; i++)cin>>a[i];dfs(1,1);cout<<ans;return 0;
}

P2372 yyy2015c01挑战算周长
题意挺绕的,简单来说就是求连通块的周长。连通块内的每个点贡献的周长确定,应该看其上下左右又没有碰墙或不属于连通块的点。

#include <bits/stdc++.h>
#define eps 1e-15
using namespace std;
int n,m,visit[25][25],nx[8]={-1,1,0,0,-1,-1,1,1},ny[8]={0,0,-1,1,-1,1,1,-1},ans;
char a[25][25];
void dfs(int x,int y){if(visit[x][y] || a[x][y]=='.')return;visit[x][y]=1;for(int k=0; k<8; k++){int xx=x+nx[k],yy=y+ny[k];if(xx>=1&&xx<=n&&yy>=1&&yy<=m)dfs(xx,yy);if(k<=3 && (xx>n || xx<1 || yy<1 || yy>m || a[xx][yy]=='.'))ans++;}
}int main()
{int x,y;cin>>n>>m>>x>>y;for(int i=1; i<=n; i++)for(int j=1; j<=m; j++)cin>>a[i][j];dfs(x,y);cout<<ans;return 0;
}

CF510B Fox And Two Dots
P1665 正方形计数

回溯

对于回溯算法,我现在也没有深入了解,只是在课上听了听,只敲了一个图的m着色问题。
回溯用深度优先搜索的方法搜索解空间,并通过剪枝去掉不可能产生解的子空间,回溯的空间诉求和深搜是一样的(废话。。。)。

#include <bits/stdc++.h>
#define eps 1e-15
using namespace std;
int n,k,m,a[105][105],co[105],ans;
bool judge(int i){for(int j=1; j<i; j++){if(a[i][j]==1 && co[i]==co[j])return false;}return true;
}
void mapColor(int i){if(i>n)ans++;else {for(int j=1; j<=m ;j++){co[i]=j;if(judge(i))mapColor(i+1);}}
}int main()
{cin>>n>>k>>m;int r,c;for(int i=1 ;i<=k; i++){cin>>r>>c;a[r][c]=1;a[c][r]=1;}mapColor(1);cout<<ans;return 0;
}

广搜

广搜是一层一层的进行搜索,每找到一个符合条件的结点就入队,在下一次循环出队,直到队空或产生最终结果。
每一层的状态都是最优的,但需要大量空间,存储每个结点产生的状态。
P1443 马的遍历
应该算是广搜的模板题了。

#include <bits/stdc++.h>
#define eps 1e-15
using namespace std;
int visit[405][405],nx[8]={-2,-1,1,2,2,1,-1,-2},ny[8]={1,2,2,1,-1,-2,-2,-1};
struct horse{int xx,yy,p;horse(int xx,int yy,int pp){make(xx,yy,pp);}void make(int xxx,int yyy,int pp){xx=xxx;yy=yyy;p=pp;}
};
queue<horse> q;
int main()
{int n,m,x,y,a[405][405],num=0;cin>>n>>m>>x>>y;memset(visit,0,sizeof(visit));for(int i=1; i<=n; i++)for(int j=1; j<=m; j++)a[i][j]=-1;visit[x][y]=1;horse t(x,y,0);q.push(t);while(!q.empty()){t=q.front();q.pop();x=t.xx,y=t.yy;num=t.p;a[x][y]=t.p;//visit[x][y]=1;可能造成同一个点多次入队,在数据量大时就会MLEfor(int i=0; i<8; i++){int xx=x+nx[i],yy=y+ny[i];if(xx>=1&&xx<=n&&yy>=1&&yy<=m && !visit[xx][yy])t.make(xx,yy,num+1),q.push(t),visit[xx][yy]=1;}}for(int i=1; i<=n; i++){for(int j=1; j<=m; j++)printf("%-5d",a[i][j]);printf("\n");}return 0;
}

P1746 离开中山路
找到最终结果直接结束

#include <bits/stdc++.h>
#define eps 1e-15
using namespace std;
int ans[1005][1005],a[1005][1005];
int main()
{int n,x1,x2,y1,y2;int nx[4]={-1,1,0,0},ny[4]={0,0,-1,1};queue<pair<int,int>> q;cin>>n;for(int i=1; i<=n; i++)for(int j=1; j<=n; j++)scanf("%1d",&a[i][j]);cin>>x1>>y1>>x2>>y2;pair<int,int> t(x1,y1);q.push(t);a[x1][y1]=1;while(!q.empty()){t=q.front();q.pop();x1=t.first,y1=t.second;for(int i=0; i<4; i++){int xx=x1+nx[i],yy=y1+ny[i];if(xx>=1&&xx<=n&&yy>=1&&yy<=n&&a[xx][yy]==0)a[xx][yy]=1,ans[xx][yy]=ans[x1][y1]+1,t=make_pair(xx,yy),q.push(t);}if(ans[x2][y2]!=0)break;//找到结果一定最优,直接退出}cout<<ans[x2][y2];return 0;
}

P1332 血色先锋队
如有错误或不足,还请您指出!

深搜+回溯+广搜小结相关推荐

  1. Go 分布式学习利器(15) -- Go 实现 深搜和广搜

    强化语法,回顾算法. 通过Go语言实现 深度优先搜索 和 广度优先搜索,来查找社交网络中的三度好友关系(三度指的是一个节点到 其相邻节点 到 其相邻节点的节点 ,图递增三层好友关系). 涉及到的Go语 ...

  2. 深搜和广搜(初学者)

    搜索入门 最近对搜索有了一点浅显的了解,想跟大家分享分享. 说起来我也是初学者,恰巧有些自己的理解,想起来自己开始学习搜索的情况,真是一把鼻子一把泪啊.所以想把我领悟的过程,看到的一些基础的我觉得好的 ...

  3. 深搜和广搜的原理及优缺点

    深搜原理 深搜,顾名思义,是深入其中.直取结果的一种搜索方法. 如果深搜是一个人,那么他的性格一定倔得像头牛!他从一点出发去旅游,只朝着一个方向走,除非路断了,他绝不改变方向!除非四个方向全都不通或遇 ...

  4. [数据结构] 迷宫问题(栈和队列,深搜和广搜)

    代码: #include <iostream> #include <string.h> #include <stack> #include <queue> ...

  5. 搜索算法-深搜与广搜

    1.深搜与回溯法 *本文主要是供自己复习,或者做笔记总结使用,专业性有待考量,如果遇到不对的地方还请指出来. 什么是回溯法?枚举每一个填空的选项,然后判断这个选项是否合法.如果合法则继续填写下一个选项 ...

  6. 深搜、广搜、搜索剪枝

    搜索与回溯讲解 文章目录 深搜 方向向量: DFS代码: 题目讲解: 八皇后问题 字符序列 自然数的拆分 广搜 BFS代码: 题目讲解: 瓷砖 关系网络 bfs与dfs的用途与区别 搜索剪枝 可行性剪 ...

  7. 算法之路——深搜、广搜(简单搜索)

    搜索 通过一定的顺序,枚举每一个数据(经常会通过一些判断条件去掉无意义的数据,即剪枝),找到想要的数据的过程. 深度优先搜索(dfs) 深度优先搜索属于图算法的一种,是一个针对图和树的算法,应为缩写为 ...

  8. 专题一:简单搜索、深搜、广搜

    挑战程序设计竞赛(课后题难题汇总) 1. AOJ 0033 Ball(贪心) #include<cstdio> #include<algorithm> using namesp ...

  9. 深搜DFS\广搜BFS 图初步入门

    首先,不管是BFS还是DFS,由于时间和空间的局限性,它们只能解决数据量比较小的问题. 深搜,顾名思义,它从某个状态开始,不断的转移状态,直到无法转移,然后退回到上一步的状态,继续转移到其他状态,不断 ...

最新文章

  1. 深度学习:知识回收(Lecture3+4 PLA+Decision Tree)
  2. 重磅!2017年度互联网转型企业TOP5发布 | 2017极客大奖年度评选
  3. 八代i7装服务器系统2012,八代I7能装win7系统吗,会影响性能吗-8代win7,8代cpu完美装win7...
  4. 国内开源软件镜像网站大全
  5. mysql010函数使用.单行函数.多行函数
  6. Docker基础入门及示例
  7. grep 显示包含两个关键字_linux三剑客之-grep
  8. docker安装nginx,配置nginx,并成功访问
  9. Redis面试题及分布式集群
  10. 滑铁卢大学计算机科学双录取,滑铁卢大学双录取要求
  11. java使用Pattern、Matcher调用正则表达式
  12. 企业如何选择固定资产管理系统?
  13. 关于对接支付接口遇到的问题(微信和支付宝)
  14. 1483. 纪念品分组 输出好忧桑…………
  15. python数据采集培训
  16. Json对象和string之间的转换
  17. 清理工作区git clean -fd
  18. 计算机组织与结构性能设计答案,计算机组织及结构—性能设计第八版答案-COA8e.pdf...
  19. windows程序提权方法
  20. 公司旅游--金华武义二日游

热门文章

  1. MiniUI:学习笔记
  2. Elasticsearch集群传输层安全配置
  3. 智能电子压力开关的组成
  4. suse linux远程,开启SUSE的VNC远程控制
  5. vnc远程控制,vnc远程控制是怎么实现的?使用教程
  6. iOS开发之SwiftEventBus发布-订阅通信
  7. html css文字颜色代码,html的颜色怎么 HTML字体颜色代码怎么获取
  8. Jbuilder 9.0光标错位问题
  9. SQL Server 2008转换成sql 2000数据库
  10. php字符集编码转换,php编码转换_php编码转换函数