深度优先搜索是一种用于遍历或搜索树或图的算法。所谓深度优先,就是说每次都尝试向更深的节点走。
要说个人理解的话,我的理解大概就是这样:
有一个人去某景区旅游,他现在在景区入口,景区里的一些路,有的能通到出口,有的不能。
这个人呢很倔强,他要一条一条去走,不走到路的尽头绝不回头。
他从第一条路走下去,走到头发现没路了,再回头到上一个分叉点,记下来这个分叉走过了;然后走另一个分叉,全部分叉走完了,再回到分叉点,再往回退一个分叉,记下来这个大分叉走过了没有路,然后走下一个分叉……
如果把这样一个景区抽象为一个图,那么也就是说,深度优先的搜索就是每次都尝试向更深的节点走。
DFS 搜索的实现方式一般是递归。也就是递归调用自身。在每次 DFS 遍历中都会对访问过的点打上标记,在遍历图的时候跳过已标记的点,以确保每个点只访问一次。
复杂度
O(n+m) |
O(m)
实现
寻找路线(走迷宫)
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
| bool DFS(int r,int c){ visited[r][c]=true;
int dr[]={-1, 1, 0, 0}; int dc[]={0, 0, -1, 1};
if()return true;
for(int d=0;d<4;++d){ int tr=r+dr[d]; int tc=c+dc[d];
if(inMap(tr,tc)&&*&&!visited[tr][tc]) if(DFS(tr,tc)) return true; } return false; }
bool inMap(int r,int c){ return r>=0&&r<n&&c>=0&&c<m; }
|
上述代码调用 DFS 时,传入起点坐标,返回 true
则找到,false
则没找到。
例题
AC 代码:
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
| #include<iostream> using namespace std;
char map[505][505]; bool visited[505][505]; int n,m;
bool DFS(int,int); bool inMap(int,int);
int main(){ cin >> n >> m; for(int i=0;i<n;++i) for(int j=0;j<m;++j) cin >> map[i][j]; int startx,starty; for(int i=0;i<n;++i) for(int j=0;j<m;++j) if(map[i][j]=='s'){ startx=i; starty=j; } bool res=DFS(startx,starty); cout << (res?"Yes\n":"No\n"); return 0; }
bool DFS(int r,int c){ visited[r][c]=true; int dr[]={-1, 1, 0, 0}; int dc[]={0, 0, -1, 1};
if(map[r][c]=='g')return true;
for(int d=0;d<4;++d){ int tr=r+dr[d]; int tc=c+dc[d]; if(inMap(tr,tc)&&map[tr][tc]!='#'&&!visited[tr][tc]) if(DFS(tr,tc)) return true; } return false; }
bool inMap(int r,int c){ return r>=0&&r<n&&c>=0&&c<m; }
|
AC 代码 (已经过处理):
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
| #include <iostream> using namespace std;
char matrix[30][40]; int count = 0;
void DFS(int, int);
int main() { for (int i = 0; i < 30; ++i) for (int j = 0; j < 40; ++j) cin >> matrix[i][j];
DFS(0, 0); cout << count << endl; return 0; }
void DFS(int x, int y) { if (x < 0 || x >= 30 || y < 0 || y >= 40 || matrix[x][y] != '0') return; count++; matrix[x][y] = '2'; DFS(x + 1, y); DFS(x - 1, y); DFS(x, y + 1); DFS(x, y - 1); }
|
在这里面没有单独存储已经遍历过的位置,是因为题目要求每走一步,就将这个地方标记为 2,也相当于已经标记过了。
AC 代码(已经过处理):
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
| #include <iostream> #include <cmath> using namespace std;
char matrix[30][60]; bool visited[30][60]; int count=0,cntmax=0; void DFS(int,int);
int main() { for(int i=0;i<30;++i) for(int j=0;j<60;++j) cin >> matrix[i][j];
for(int i=0;i<30;++i) for(int j=0;j<60;++j){ count=0; DFS(i,j); cntmax=max(count,cntmax); }
cout << cntmax << endl; return 0; }
void DFS(int x,int y){ if(x<0||x>=30||y<0||y>=60||matrix[x][y]=='0'||visited[x][y]==1) return; visited[x][y]=1; count++;
int dx[4]={1,-1,0,0}; int dy[4]={0,0,-1,1};
for(int i=0;i<4;++i){ int nextx=x+dx[i]; int nexty=y+dy[i]; if(nextx>=0&&nextx<30&&nexty>=0&&nexty<60&&matrix[nextx][nexty]=='1'&&visited[nextx][nexty]==0){ DFS(nextx,nexty); } } }
|