DFS(深度优先搜索)和BFS(广度优先搜索)是两种搜索策略,属于基础的常用算法。
DFS顾名思义 先优先搜索深处的,可比喻为 一条路一直往下走,走到不能走的时候,原路返回,返回到有路可走,在继续走,如此循环。
看下图
DFS:
由此图我们可知,DFS一次走一条路,直到无路可走,并且,不走已经走过的路,那么我们如何让计算机知道这条路已经走过呢? 一般用二维数组,将走过的位置标记为 1,这样在递归中我们只需要加一个if语句进行判断就可以了,这样如果所有满足条件的位置都被走完,那么循环退出。
BFS:
由图可知:我们需要先把 将要搜索的节点(下标)也就是 子节点 暂时保存在队列中,然后根据队列先进先出的特性,一个个搜索。
回溯:
指的是递归函数中函数不再调用自己本身,而是返回上一层,看下面的代码:
#include<stdio.h>
void f(int n);
int count=0;
int main(void)
{
f(1);
return 0;
}
void f(int n)
{
count++;
printf("第%d次: %d: n 地址 %p\n",count, n, &n);
if (n < 4)
f(n + 1);
printf("第%d次: %d: n 地址 %p\n",count, n, &n);
return;// 只有 return的话就是返回上一层, 也可以省略。
}
运行结果:
第1次: 1: n 地址 000000000062FE30
第2次: 2: n 地址 000000000062FE00
第3次: 3: n 地址 000000000062FDD0
第4次: 4: n 地址 000000000062FDA0
第4次: 4: n 地址 000000000062FDA0
第4次: 3: n 地址 000000000062FDD0
第4次: 2: n 地址 000000000062FE00
第4次: 1: n 地址 000000000062FE30
发现问题所在了吗 全局变量 count 的值是4,也就意味着,count只累加了四次,所以 f()函数仅仅只调用了4次,因为调用4次以后,n的值已经大于了4,不满足if语句的条件,所以代码往下执行,到return;此时会返回到f()函数的上一层。同理,当我们在进行DFS搜索时,如果搜索到某个地方之后条件不成立了,那么就会回溯到该函数的上一层。
今天的例题是 : POJ 1979 一道简单的DFS入门题,自己尝试做出来之后,会加深对回溯和DFS算法的理解。
题目大意是:
一个房间里, 有N*M块砖,分为红砖和黑砖, 一个男人的初始位置标记为@ ,他只能在黑砖上走,给出数据求出这个男人最多能走几块黑砖。
所以我们用一个map[20][20]数组模拟地图, book[20][20]数组保存是否走过的状态。全都初始化为0,并且用sum来计算走的黑砖的总和,都定义为全局变量,这样方便操作;
AC代码:
#include<stdio.h>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
using namespace std;
int x,y,sum=1;
int n,m; // 行 列
int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
char map[20][20];
int book[20][20];
void input(int n,int m){
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
cin>>map[i][j];
if(map[i][j]=='@')
x=i,y=j;
}
}
}
void dfs(int x,int y){
for(int i=0;i<4;i++){
int gx=x+next[i][0];
int gy=y+next[i][1];
if(gx>=0&&gx<m&&gy>=0&&gy<n&&book[gx][gy]!=1&&map[gx][gy]=='.'){
sum++;
book[gx][gy]=1;
dfs(gx,gy);
}
}
return;
}
void ahhh(){
while(cin>>n>>m&&n||m)
{
memset(map,0,sizeof(map));
memset(book,0,sizeof(book));
input(n,m);
dfs(x,y);
cout<<sum<<endl;
sum=1;
}
}
int main()
{
ahhh();
return 0;
}