虽然DFS和BDFS都是搜索方法,但是在不同的问题中两者的效率还是会有差别的。 dfs实现的方式是递归或者非递归,但是其本质还是栈 。bfs的本质则是队列 。 本质不同,他们的搜索方式必然是不同的,dfs是在其中可选项中选择一个,然后再以其再递归如果不满足了就回溯。 而bfs就不同,bfs是选择一个元素,其元素的周围的可选项全部入队,然后出队首元素,出对的元素的周围可选项再全部入队,如此。 DFS类比于撞南墙(递归),撞到头不好走了就返回(回溯);BFS就相当于水面上的涟漪,一圈一圈的扩散。 具体概念上的异同点可以查阅资料,下面举例几道题感受一下:
首先看一道经典例题:八皇后问题 。题目链接 对于要求一个棋子,其对应的所在行,所在列,所在两个对角线都不能有其他的棋子存在。
那么b[j]==0即为搜在列没有棋子。 c[i+j]==0代表其左下到右上的斜对角线上没有棋子,因为你会发现,i+j相同,即代表行+列的和相同,满足这样的情况,就是同一对角线上的棋子,且是左下到右上的斜对角线。 d[i-j+n]==0代表的是左上到右下的斜对角线的棋子们。i-j相同,即行-列的差相同,就是同一从左上到右下的斜对角线。因为i-j会有小于0的情况,所以,要+n。
程序的思想是:从第一行开始,对每一行的每一个列递归查找。如果满足条件就标记此处,在此下棋。如果下的棋子的个数达到n,就按条件输出,如果没有达到,就递归搜索下一行。如果这一行的所有列都搜索过了,且没有满足条件的地方,那么就出递归,消除上一行中下棋的地方,重新再这一行中的下面没有寻找的列中找到满足下棋的地方,如果找到就向下递归,如果这行也没有找到,就回溯到上一行,取消掉这一行中所下的棋子。 如此过程即可。 这是一个典型的深度优先遍历 的思想。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #include <iostream> using namespace std;int a[1000 ],b[1000 ],c[1000 ],d[1000 ];int n,s;void shuchu () { int i; s++; if (s<=3 ){ for (int i=1 ;i<=n;i++){ cout<<a[i]<<" " ; } cout<<endl; } } int search (int i) { int j; for (j=1 ;j<=n;j++){ if (b[j]==0 &&c[i+j]==0 &&d[i-j+n]==0 ){ a[i]=j; b[j]=1 ; c[i+j]=1 ; d[i-j+n]=1 ; if (i==n) shuchu (); else search (i+1 ); b[j]=0 ; c[i+j]=0 ; d[i-j+n]=0 ; } } } int main () { cin>>n; search (1 ); cout<<s<<endl; return 0 ; }
接着看一道题:单词方阵 题目链接
解题思路:首先先要找到一个字符串是’y’,然后以这个字符为循环起点,分别对这个点的八个不同的方向去循环。选择一个方向,循环这个方向上的所有字符串,如果所有的字符串都和所求字符串相同,就将这个方向保存在ans数组种,如果字符串有一个不同或者越界,就至标记flag=0,跳出字符串的循环,开始下一个方向的循环。
其实这题不太算严谨的DFS ,只能叫循环。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #include <iostream> #include <string> using namespace std;const int maxn=110 ;const int dx[]={1 ,1 ,1 ,0 ,0 ,-1 ,-1 ,-1 };const int dy[]={1 ,0 ,-1 ,1 ,-1 ,0 ,1 ,-1 };const string cmp="yizhong" ;char a[maxn][maxn],ans[maxn][maxn];int n;void dfs (int x,int y) { for (int i=0 ;i<8 ;i++){ int flag=1 ; for (int j=1 ;j<=6 ;j++){ int xx=x+j*dx[i]; int yy=y+j*dy[i]; if (xx<1 ||xx>n||yy<1 ||yy>n){ flag=0 ; break ; } if (cmp[j]!=a[xx][yy]){ flag=0 ; break ; } } if (flag==0 ) continue ; for (int j=0 ;j<=6 ;j++){ int xx=x+j*dx[i]; int yy=y+j*dy[i]; ans[xx][yy]=a[xx][yy]; } } return ; } int main () { cin>>n; for (int i=1 ;i<=n;i++){ for (int j=1 ;j<=n;j++){ cin>>a[i][j]; } } for (int i=1 ;i<=n;i++){ for (int j=1 ;j<=n;j++){ if (a[i][j]=='y' ) dfs (i,j); } } for (int i=1 ;i<=n;i++){ for (int j=1 ;j<=n;j++){ if (ans[i][j]==0 ) ans[i][j]='*' ; cout<<ans[i][j]; } cout<<endl; } return 0 ; }
再看一个题:迷宫 题目链接
这题的思路无独有偶,可以用深度搜索遍历 。 只是其中的tt数组有两个功能,一个是表示是否这个为陷阱,还有一个功能是要他来表示边界,因为tt数组定义在栈中,即为全局变量,所以默认都是0,所以又要表示出边界,只能初始化为1。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <iostream> using namespace std;int dx[4 ]={0 ,0 ,1 ,-1 };int dy[4 ]={-1 ,1 ,0 ,0 };int tt[6 ][6 ];bool temp[6 ][6 ];int n,m,t;int total;int tx,ty;int sx,sy,fx,fy;void dfs (int x,int y) { if (x==fx&&y==fy){ total++; return ; } else { for (int i=0 ;i<=3 ;i++){ if (temp[x+dx[i]][y+dy[i]]==0 &&tt[x+dx[i]][y+dy[i]]==1 ){ temp[x][y]=1 ; dfs (x+dx[i],y+dy[i]); temp[x][y]=0 ; } } } } int main () { cin>>n>>m>>t; cin>>sx>>sy>>fx>>fy; for (int i=1 ;i<=n;i++){ for (int j=1 ;j<=m;j++){ tt[i][j]=1 ; } } for (int k=1 ;k<=t;k++){ cin>>tx>>ty; tt[tx][ty]=0 ; } dfs (sx,sy); cout<<total<<endl; return 0 ; }
填涂颜色 题目链接 DFS题解如下: 注意下题再输入的时候是从i=1,j=1处输入的,但是数组的行,列都是从0,0开始的,所以,我们输入的数组,没有贴着数组输入,输入的数字是被外面一圈0包围着的。这样,就不会如果输入的数据一开始就是包围圈,递归就停止递归了。就不会出现上述这种情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include <iostream> using namespace std;int a[32 ][32 ],b[32 ][32 ];int dx[5 ]={0 ,-1 ,1 ,0 ,0 };int dy[5 ]={0 ,0 ,0 ,-1 ,1 };int n,j,i;void dfs (int x,int y) { int i; if (x<0 ||x>n+1 ||y<0 ||y>n+1 ||a[x][y]!=0 ) return ; a[x][y]=1 ; for (i=1 ;i<=4 ;i++){ dfs (x+dx[i],y+dy[i]); } } int main () { cin>>n; for (i=1 ;i<=n;i++){ for (j=1 ;j<=n;j++){ cin>>b[i][j]; if (b[i][j]==0 ) a[i][j]=0 ; else a[i][j]=2 ; } } dfs (0 ,0 ); for (i=1 ;i<=n;i++){ for (j=1 ;j<=n;j++){ if (a[i][j]==0 ) cout<<2 <<' ' ; else cout<<b[i][j]<<' ' ; } cout<<'\n' ; } return 0 ; }
字串变化 题目链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 #include <iostream> #include <queue> #include <string> #include <map> using namespace std;const int maxn=15 ;string aa; string b; int n,ans;struct node { string a; int step; }; string shi[maxn]; string zhong[maxn]; map<string,int > ma; string pin (const string &a,int i,int j) { string ans="" ; if (i+shi[j].length ()>a.length ()){ return ans; } for (int k=0 ;k<shi[j].length ();k++){ if (a[i+k]!=shi[j][k]) return ans; } ans=a.substr (0 ,i); ans+=zhong[j]; ans+=a.substr (i+shi[j].length ()); return ans; } void bfs () { queue<node> q; node s; s.a=aa; s.step=0 ; q.push (s); while (!q.empty ()){ node u=q.front (); q.pop (); string temp; if (ma.count (u.a)==1 ){ continue ; } if (u.a==b){ ans=u.step; break ; } ma[u.a]=1 ; for (int i=0 ;i<u.a.length ();i++){ for (int j=0 ;j<n;j++){ temp=pin (u.a,i,j); if (temp!="" ){ node v; v.a=temp; v.step=u.step+1 ; q.push (v); } } } } if (ans>10 ||ans==0 ){ cout<<"NO ANSWER!" <<endl; } else { cout<<ans<<endl; } } int main () { cin>>aa>>b; while (cin>>shi[n]>>zhong[n]) n++; bfs (); return 0 ; }