Mrli
别装作很努力,
因为结局不会陪你演戏。
Contacts:
QQ博客园

ACM-DFS、BFS

2020/11/05 ACM
Word count: 1,422 | Reading time: 7min

深度优先搜索(DFS)

从某个状态,不断转移状态直到无法转移,然后回退到前一步的状态,继续转移到其他状态,如此不断重复,直到找到最终解. ====> 递归函数

隐式的用到了栈(stack)

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
//[部分和问题]
#include <iostream>
#define MAXN 10000
int n,k;
int s[MAXN];
using namespace std;

bool dfs(int i,int sum){
if( i == n ) return sum == k;//如果前n项计算过了,返回sum=k是否相等

if ( dfs(i+1 , sum) ) return true; //不加上s[i]的情况;
if ( dfs(i+1, sum + s[i] )) return true; //加上s[i]的情况
return false; //无论加不加上s[i]
}

void input(){
cin >> n;
for(int i=0;i<n;i++) cin >> s[i];
cin >> k;
}

int main(){
input();
if (dfs(0,0)) cout << "YES";
else cout <<"NO";
return 0;
}

laking countiing

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
//[laking countiing]
#include <iostream>
#include <cstdio>
#define MAXN 10000
using namespace std;
int N,M;
char field[MAXN][MAXN]={
{"W........WW."},
{".WWW.....WWW"},
{"....WW...WW."},
{".........WW."},
{".........W.."},
{"..W.......W."},
{".W.W.....WW."},
{"W.W.W.....W."},
{".W.W......W."},
{"..W.......W."}
};

void dfs(int x,int y){
field[x][y] = '.';
//循环遍历移动的8个方向,检测八连通位置
for(int dx=-1;dx<=1;dx++)
for(int dy=-1;dy<=1;dy++){
int nx=x+dx; //移动后的结果为(nx,ny)
int ny=y+dy;
if( (0 <= nx && nx< N) && (0 <= ny && ny < M) && field[nx][ny]=='W') dfs(nx,ny); //此处为做题的关键 : 不断
}
return ;
}

void solve(){
int res = 0; //水坑数量
for(int i=0;i<N;i++)
for(int j=0;j<M;j++){
if(field[i][j] == 'W'){
dfs(i,j);
res++;
}
}
printf("%d\n",res);
}

void printLake(){
N=10;M=12;
for(int i=0;i<N;i++){
for(int j=0;j<M;j++)
cout << field[i][j] ;
cout << endl;
}
}

int main(){
N=10;
M=12;
solve();
return 0;
}

宽度优先搜索(BFS)

总是优先搜索距离初始状态最近的状态,复杂度 = O(状态书 * 转移的方式)

显式利用队列(queue),搜索时首先将初始状态添加到队列里,此后从队列的最前端不断取出状态,吧从该状态可以转移到的状态中尚未访问过的部分加入队列,如此往返,直至队列被取空或是找到了问题的解

广度优先搜索思想

设图G的初态是所有顶点均未访问,在G 中任选一顶点i作为初始点,则广度优先搜索的基本思想是:

  • (1)从图中的某个顶点V出发,访问之;并将其访问标志置为已被访问,即visited[i]=1;
  • (2)依次访问顶点V的各个未被访问过的邻接 点,将V的全部邻接点都访问到;
  • (3)分别从这些邻接点出发,依次访问它们的未被访问过的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接 点”被访问,直到图中所有已被访问过的顶点的邻接点都被访问到。依此类推,直到图中所有顶点都被访问完为止 。

广度优先搜索在搜索访问一层时,需要记住已被访问的顶点,以便在访问下层顶点时,从已被访问的顶点出发搜索访问其邻接点。所以在广度优先搜索中需要设置一个队列Queue,使已被访问的顶点顺序由队尾进入队列。在搜索访问下层顶点时,先从队首取出一个已被访问的上层顶点,再从该顶点出发搜索访问它的各个邻接点。

1
2
3
4
5
6
7
8
9
10
11
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
.........WW.
..W.......W.
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.
1
2
3
4
5
6
7
8
9
10
11
{W........WW.}
{.WWW.....WWW}
{....WW...WW.}
{.........WW.}
{.........W..}
{.........WW.}
{..W.......W.}
{.W.W.....WW.}
{W.W.W.....W.}
{.W.W......W.}
{..W.......W.}

2019蓝桥杯省赛–maze

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
#include <bits/stdc++.h>
#include <string>
#include <queue>
/*
010010
001000
000101
110000

访问次数:9
访问次序:DRDRDRRR
*/
using namespace std;
typedef pair<int ,int> State;

const int maxn = 1000;
const int row = 4;
const int col = 6;
//const int INF = 10000000;

char maze[row+1][col+1];
int visited[row+1][col+1]; //是否访问过,记录次数
string trace[row+1][col+1]; //记录每次移动的方向

int X[] = {-1,0,1,0}; // 这边可能定义错了,这个对应的是行
int Y[] = {0,1,0,-1}; // 这个对应的是列,而不是X,Y
string sarr[] = {"U","R","D","L"};
int x=1;
int y=1;

void bfs(){
queue<State> q;
// 起点
q.push(State(x,y));
while( !q.empty() ){
// 取状态
State s = q.front();
q.pop();

if( x == row && y == col ) break;
// 到达终点

// 一个数组记录四个方向
for( int i = 0 ; i < 4; i++){
int nx = s.first + X[i];
int ny = s.second + Y[i];
if( nx >= 1 && nx <= row &&
ny >= 1 && ny <= col &&
maze[nx][ny] != '1'&&
visited[nx][ny] == 0 )
{
//cout << nx << ny << endl;
visited[nx][ny] = 1;
//cout << maze[nx][ny] << sarr[i] << endl;
//cout << endl;
visited[nx][ny] = visited[s.first][s.second] +1;
trace[nx][ny] = trace[s.first][s.second] + sarr[i];
q.push(State(nx,ny));
}
}
}
cout <<"times:"<< visited[row][col] <<endl;
cout <<"order:"<< trace[row][col] <<endl;
}

int main(){
// 初始化
for(int i=1 ; i <= row ; i++)
for(int j= 1; j <= col ; j++)
visited[i][j] = 0;
// 起点为(1,1)
visited[1][1] = 1;

//处理输入
for(int i=1 ; i <= row ; i++){
for(int j= 1; j <= col ; j++)
scanf("%c",&maze[i][j]);
getchar();
}


bfs();
return 0;
}

Author: Mrli

Link: https://nymrli.top/2019/03/07/ACM-DFS、BFS/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

< PreviousPost
程序设计周cpp学习笔记
NextPost >
ACM-快速幂
CATALOG
  1. 1. 深度优先搜索(DFS)
    1. 1.1. laking countiing
  2. 2. 宽度优先搜索(BFS)
    1. 2.1. 2019蓝桥杯省赛–maze