深度优先搜索DFS (poj2386,poj1979, poj3009,poj1321,aoj0033,aoj0118)

深度优先搜索(DFS)

往往利用递归函数实现(隐式地使用栈)。

深度优先从最开始的状态出发,遍历所有可以到达的状态。由此可以对所有的状态进行操作,或列举出所有的状态。

1.poj2386 Lake Couting

题意:八连通被认为连接在一起,求总共有多少个水洼?

Sample Input:

10 12
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.

Sample Output

3

思路:从任意W开始,一次DFS把连通的.全部变为W,遍历图直到没有.为止,进行DFS次数即为水洼的个数。代码:
 1 #include<iostream>
 2 using namespace std;
 3 int N, M;
 4 char pond[100][100]; //global variable
 5 void dfs(int i, int j){ // 注意参数设计,要不要返回值
 6     pond[i][j] = ‘.‘;
 7     for(int dx = -1; dx <= 1; ++dx){ //八连通遍历方式,四连通往往事先开好数组,见后续题目
 8         for(int dy = -1; dy <= 1; ++dy){
 9             int x = i + dx, y = j + dy;
10             if(x >= 0 && x < N && y >= 0 && y < M && pond[x][y] == ‘W‘){
11                 dfs(x,y);
12             }
13         }
14     }
15     return;
16 }
17 int main(){
18     cin >> N >> M;
19     for(int i = 0; i < N; ++i){
20         for(int j = 0; j < M; ++j){
21             cin >> pond[i][j];
22         }
23     }
24
25     int count = 0;
26     for(int i = 0; i < N; ++i){
27         for(int j = 0; j < M; ++j){
28             if(pond[i][j] == ‘W‘){
29                 dfs(i,j);
30                 count ++;
31             }
32         }
33     }
34     cout << count << endl;
35 }

2.poj1979 Red and Black

题意:@表示起点,可以上下左右四方向走,"."为黑色,可以走,“#”为红色,不可以走,问可以到达多少个黑色位置?

Sample Input

6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
11 9
.#.........
.#.#######.
.#.#.....#.
.#.#.###.#.
.#.#[email protected]#.#.
.#.#####.#.
.#.......#.
.#########.
...........
11 6
..#..#..#..
..#..#..#..
..#..#..###
..#..#..#@.
..#..#..#..
..#..#..#..
7 7
..#.#..
..#.#..
###.###
[email protected]
###.###
..#.#..
..#.#..
0 0

Sample Output

45
59
6
13
思路:从起点处DFS遍历即可,当前点为“.”则将其改为“#”,result++,并以该点出发继续遍历。代码:
 1 #include<iostream>
 2 using namespace std;
 3 char rect[20][20];
 4 int result = 0;  //全局的result
 5 int dx[4] = {-1,0,0,1};  //四连通处理方法
 6 int dy[4] = {0,1,-1,0};
 7 int W = 1, H = 1;
 8 void dfs(int sx, int sy){
 9     rect[sx][sy] = ‘#‘;
10     result++;
11     for(int i = 0; i < 4; ++i){
12         int x = sx + dx[i], y = sy + dy[i];
13         if(x >= 0 && x < H && y >= 0 && y < W && rect[x][y] == ‘.‘){
14             dfs(x,y);
15         }
16     }
17     return ;
18 }
19 int main(){
20     while(W != 0 && H != 0){
21         cin >> W >> H;
22         if(W == 0 && H == 0){
23             return 0;
24         }
25         int sx, sy;
26         for(int i = 0; i < H; ++i){
27             for(int j = 0; j < W; ++j){
28                 cin >> rect[i][j];
29                 if(rect[i][j] == ‘@‘){
30                     sx = i;
31                     sy = j;
32                 }
33             }
34         }
35         dfs(sx, sy);
36         cout << result << endl;
37         result = 0;
38     }
39     return 0;
40 } 

3.aoj0118 Property Distribution

题意: 苹果是@,梨是#, 蜜柑是*。 四连通且相同品种在一个区域。计算每组数据区域的个数。

Sample Input:

10 10
####*****@
@#@@@@#*#*
@##***@@@*
#****#*@**
##@*#@@*##
*@@@@*@@@#
***#@*@##*
*@@@*@@##@
*@*#*@##**
@****#@@#@
0 0

Output for the Sample Input

33
思路:类似第一题的池塘数个数的思路,DFS遍历,将遍历完毕的节点改为不同于上述三种标志的第四种标志,如“X”,     并且在DFS函数中加入标志参数用于判断同类水果区域,一次DFS,result++,当所有标志为X时,遍历结束。代码:
 1 #include<iostream>
 2 using namespace std;
 3 char garden[100][100];
 4 int H = 1, W = 1;
 5 int result = 0;
 6 int dx[4] = {-1,0,0,1};
 7 int dy[4] = {0,1,-1,0};
 8 void dfs(int sx, int sy,char c){ //加入char判断是否同一类
 9     garden[sx][sy] = ‘x‘;
10     for(int i = 0; i < 4;++i){
11         int x = sx + dx[i], y = sy + dy[i];
12         if(x >= 0 && x < H && y >= 0 && y < W && garden[x][y] == c){
13             dfs(x,y,c);
14         }
15     }
16     return;
17 }
18 int main(){
19     while(H != 0 && W != 0){
20         cin >> H >> W;
21         if(H == 0 && W == 0){
22             return 0;
23         }
24         for(int i = 0; i < H; ++i){
25             for(int j = 0; j < W; ++j){
26                 cin >> garden[i][j];
27             }
28         }
29         for(int i = 0; i < H; ++i){
30             for(int j = 0; j < W; ++j){
31                 if(garden[i][j] != ‘x‘){
32                     dfs(i,j,garden[i][j]);
33                     result++;
34                 }
35             }
36         }
37         cout << result << endl;
38         result = 0;
39     }
40 }
4.aoj0033 Ball题意:A管进球,B,C管出球,给定如球顺序,判断能否移动挡板,使得B,C出球顺序均为从下往上标号递增。

Sample Input

2
3 1 4 2 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1

Output for the Sample Input

YES
NO
思路:DFS遍历,一个参数记录当前到第几个球,另外两个记录当前B,C顶端球得数值,以便于比较。代码:
 1 #include<iostream>
 2 using namespace std;
 3 int A[10];
 4 bool dfs(int start, int topB, int topC){  //有返回值的DFS
 5     if(start == 9){  //最后一个球啦
 6         if(A[start] > topB || A[start] > topC){
 7             return true;
 8         }
 9         else{
10             return false;
11         }
12     }
13     bool b1 = false, b2 = false;
14     if(A[start] > topB){  //B可以放,放进去试
15         b1 = dfs(start+1, A[start], topC);
16     }
17     if(A[start] > topC){ //C可以放,放进去试
18         b2 = dfs(start+1,topB,A[start]);
19     }
20     return (b1 || b2 );   //B,C都不可以放的时候,返回false,否则true
21 }
22 int main(){
23     int N;
24     cin >> N;
25     for(int i = 0; i < N; ++i){
26         for(int j = 0; j < 10; ++j){
27             cin >> A[j];
28         }
29         bool result = dfs(0,0,0);
30         if(result == true){
31             cout << "YES" << endl;
32         }
33         else{
34             cout << "NO" <<endl;
35         }
36     }
37     return 0;
38 }

 5. poj3009 Curling 2.0

题意:

可以沿上下左右走到障碍物,碰到障碍物后停下,障碍物消失,然后可以继续出发,出界算失败,超过十步算失败,问能否从S到G,

不能输出-1,能输出最少步数。(0路径,1障碍物,2起点,3终点)

Sample Input

2 1
3 2
6 6
1 0 0 2 1 0
1 1 0 0 0 0
0 0 0 0 0 3
0 0 0 0 0 0
1 0 0 0 0 1
0 1 1 1 1 1
6 1
1 1 2 1 1 3
6 1
1 0 2 1 1 3
12 1
2 0 1 1 1 1 1 1 1 1 1 3
13 1
2 0 1 1 1 1 1 1 1 1 1 1 3
0 0

Sample Output

1
4
-1
4
10
-1

思路:这种走到底的题目也可以用DFS,设计成无返回值,到达3后比较当前值与已有最小值的大小。注意走到底的写法(while)

代码:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<limits.h>
 4 using namespace std;
 5 int board[21][21];
 6 int W = 1, H = 1;
 7 int dx[4] = {-1,0,0,1};
 8 int dy[4] = {0,1,-1,0};
 9 int sx, sy,minStep = INT_MAX;
10 void dfs(int sx,int sy,int step){    //设计成无返回值,当board[i][j] == 3时比较当前 step+1 与最小的step并更新
11     if(step >= 10){     //剪枝
12         return;
13     }
14     for(int i = 0; i < 4;++i){
15         int x = sx + dx[i], y = sy + dy[i];
16         if(x >= 0 && x < H && y >=0 && y < W && board[x][y] != 1){
17             while(x >= 0 && x < H && y >=0 && y < W && board[x][y] != 1){ //走到底的判断
18                 if(board[x][y] == 3){
19                     if(step + 1 < minStep){
20                         minStep = step + 1;
21                         break;
22                     }
23                 }
24                 x += dx[i];
25                 y += dy[i];
26                 if(board[x][y] == 1){
27                     board[x][y] = 0;
28                     dfs(x - dx[i], y - dy[i], step + 1);
29                     board[x][y] = 1;    // 恢复状态
30                 }
31             }
32         }
33     }
34     return;
35 }
36
37 int main(){
38     while(W != 0 && H != 0){
39         cin >> W >> H;
40         if(W == 0 && H == 0){
41             return 0;
42         }
43         memset(board,0,sizeof(board));
44         for(int i = 0; i < H; ++i){
45             for(int j = 0; j < W; ++j){
46                 cin >> board[i][j];
47                 if(board[i][j] == 2){
48                     sx = i;
49                     sy = j;
50                 }
51             }
52         }
53         dfs(sx,sy,0);
54         if(minStep == INT_MAX){
55             cout << "-1" << endl;
56         }
57         else{
58             cout << minStep << endl;
59         }
60         minStep = INT_MAX;
61     }
62     return 0;
63 }

6.poj1321 棋盘问题

题意:n*n矩阵形状的棋盘(“#”为可摆放棋盘区域,“.”为不可摆放空白区域),要摆放k个棋子,同行同列不能有两个,共多少种方案?

Sample Input

2 1
#.
.#
4 4
...#
..#.
.#..
#...
-1 -1

Sample Output

2
1

思路:DFS的思路,一行一行的确定摆放位置,开一个数组place[8]记录哪一列已经有摆放。注意k如果小于N时,可以有某一行不摆放元素,所以代码24行 DFS(row+1,num) 必须添加。

代码:
 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 int N = 1,K = 1;
 5 char chess[8][8];
 6 int result = 0;
 7 int placed[8] = {0};  //记录该列是否有摆放
 8 void dfs(int row,int num){
 9     if(num == K){   //摆放成功,方案数++
10         result++;
11         return;
12     }
13     if(row == N){
14         return;
15     }
16
17     for(int i = 0; i < N; ++i){
18         if(chess[row][i] == ‘#‘ && placed[i] == 0){
19             placed[i] = 1;
20             dfs(row + 1, num + 1);
21             placed[i] = 0;
22         }
23     }
24     dfs(row+1,num);  //!容易忽略
25
26 }
27 int main(){
28     while(N != -1 && K != -1){
29         cin >> N >> K;
30         if(N == -1 && K == -1){
31             return 0;
32         }
33         memset(chess,0,sizeof(chess));
34         memset(placed,0,sizeof(placed));
35         for(int i = 0; i < N;++i){
36             for(int j = 0; j < N; ++j){
37                 cin >> chess[i][j];
38             }
39         }
40         dfs(0,0);
41         cout << result << endl;
42         result = 0;
43     }
44
45 } 
 
时间: 2024-10-06 13:09:15

深度优先搜索DFS (poj2386,poj1979, poj3009,poj1321,aoj0033,aoj0118)的相关文章

[LeetCode OJ] Word Search 深度优先搜索DFS

Given a 2D board and a word, find if the word exists in the grid. The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be us

深度优先搜索(DFS)详解

深度优先搜索(DFS) [算法入门] 1.前言 深度优先搜索(缩写DFS)有点类似广度优先搜索,也是对一个连通图进行遍历的算法.它的思想是从一个顶点V0开始,沿着一条路一直走到底,如果发现不能到达目标解,那就返回到上一个节点,然后从另一条路开始走到底,这种尽量往深处走的概念即是深度优先的概念. 你可以跳过第二节先看第三节,:) 2.深度优先搜索VS广度优先搜索 2.1演示深度优先搜索的过程 还是引用上篇文章的样例图,起点仍然是V0,我们修改一下题目意思,只需要让你找出一条V0到V6的道路,而无需

【算法入门】深度优先搜索(DFS)

深度优先搜索(DFS) [算法入门] 1.前言深度优先搜索(缩写DFS)有点类似广度优先搜索,也是对一个连通图进行遍历的算法.它的思想是从一个顶点V0开始,沿着一条路一直走到底,如果发现不能到达目标解,那就返回到上一个节点,然后从另一条路开始走到底,这种尽量往深处走的概念即是深度优先的概念. 你可以跳过第二节先看第三节,:) 2.深度优先搜索VS广度优先搜索 2.1演示深度优先搜索的过程还是引用上篇文章的样例图,起点仍然是V0,我们修改一下题目意思,只需要让你找出一条V0到V6的道路,而无需最短

深度优先搜索(dfs)

关于深度优先搜索的总结: 1 dfs 的基本结构:  void dfs(int x){ if( x 超出边界){ return ; }else{ for(遍历){ if(未访问过){ 访问         ; 打上标记    ; dfs(x + 1) ; 去掉标记    ; //极易忘记 } } } return; } 2 用dfs求全排列: 本来好好的,结果sizeof(pointer) 就完蛋了.神秘的内存错误,而且还能正常的跑出一个不正常的结果出来. 想了解sizeof这个小妖精的看这里

python实现基础的深度优先搜索(DFS, depth first search)解决数的全排列问题

数的全排列,是一个很简单的问题,平时我们用笔用纸就能列出答案,但是数列位多的时候,排列的结果就有非常多了,例如有1,2,3,4,5,6,7,8,9这一个数列,有9个数字,则有9!(9的阶乘)这么多种结果.那是非常大的.今天我就来介绍用深度优先搜索来解决这个数的全排列的问题. 深度优先搜索 首先简单介绍一下深度优先搜索,深度优先搜索的关键在于当下该如何做,至于下一步如何做,就与当下做的一样.深度优先搜索的基本模型为: dfs(step): 判断边界:执行相关操作,返回 尝试每一种可能 for( i

深度优先搜索DFS和广度优先搜索BFS

DFS简介 深度优先搜索,从起点开始按照某个原则一直往深处走,直到找到解,或者走不下去,走不下去则回溯到前一节点选择另一条路径走,直到找到解为止. BFS简介 广度优先搜索,从起点开始先搜索其相邻的节点,由此向外不断扩散,直到找到解为止. 举例解释 从1开始去寻找5 DFS: 原则:优先选择左手边 过程:1-2-3-4-6-4-5 BFS: 队列情况:1 2.5     5.3 5出来则找到 遍历图中所有点 DFS: 原则:优先选择左手边 过程:1-2-3-4-6-4-5 BFS: 队列情况:1

深度优先搜索(DFS: Depth First Search)

深度优先搜索是一种树的遍历方式.与此对应的是广度优先搜索. ? 二叉树的优先搜索: ? 如何把一个数学问题转换为树的深度优先搜索问题: 例如:各位数之和为偶数的一个10位二进制数有几个. 我们来分析一下这个问题,首先一共有10位数,然后每一位数都只有两种状态0,1 这可以看做是一个深度为10的一个二叉树,然后用树的深度优先搜索即可解决问题. ? 用C语言实现的代码结构 void DFS(int depth) { ????if(depth==10)????????//递归出口 ????{ ????

深度优先搜索 DFS(Depath First Search, DFS)

深度优先搜索是一种枚举所有完整路径以遍历所有情况的搜索方法.(不撞南墙不回头) DFS一般用递归来实现,其伪代码思路过程一般如下: void DFS(必要的参数){    if (符和遍历到一条完整路径的尾部){        更新某个全局变量的值    }    if (跳出循环的临界条件){        return;    }    对所有可能出现的情况进行递归} 常见题型1: 代码实现: 1 #include <stdio.h> 2 const int maxn = 30; 3 in

[DFS] &amp; [BFS] poj1979 poj3009 poj3669

都比较简单,直接贴代码吧. poj1979 DFS 题目大意:给你一个二维数组,.表示可以到达,#表示障碍,@表示起始位置,问你能到达的最大地点有多少个,每次只能走上下左右 #include <iostream> #include <cstdio> #include <cstring> using namespace std; int n, m, sx, sy, ans; int pd[30][30]; char maze[30][30]; int dx[4] = {0