DFS(深搜)和BFS(广搜)

DFS(深搜)和BFS(广搜)

DFS

深度优先搜索属于图算法的一种,英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次.

举例说明:

img

上图是无向图,从A节点开始进行深度优先搜索(以下的访问次序并不是唯一的,第二个点既可以是B也可以是C,D),则我们可能得到如下的一个访问过程:

A->B->E(没有路了!回溯到B,发现还是没路,回溯到A)->C->F->H->G->D(没有路,最终回溯到A,发现A也没路了)本次搜索结束。

注意:每次到最后一个没有路的节点时,标记已经走过,上图例子中第一个没有路的节点时E,然后回溯到B,发现B也没有路了,标记走过,再回溯到A,以此类推。

举例

题目描述
​ 在一个 w∗h的矩形广场上,每一块 1∗1的地面都铺设了红色或黑色的瓷砖。小明现在站在某一块黑色的瓷砖上,他可以从此处出发,移动到上下左右四个相邻的且是黑色的瓷砖上。现在,他想知道,通过重复上述移动所能经过的黑色瓷砖数。

输入
​ 第一行两个正整数 h,w。(2≤h,w≤50)
​ 接下来输入一个二维字符矩阵,每个字符为 “.”,"#","@",分别代表黑色瓷砖,红色瓷砖,初始位置。

输出
​ 输出一个整数,表示可以到达的瓷砖数。

 样例输入
11 9
.#.........
.#.#######.
.#.#.....#.
.#.#.###.#.
.#.#..@#.#.
.#.#####.#.
.#.......#.
.#########.
.........

样例输出
59

数据规模与约定
​ 时间限制:1 s
​ 内存限制:256 M
100% 的数据保证 2≤h,w≤50​

​ 思路:从一个起点找到可走路径,标记已走过,递归调用
注意:需将此处的行列与坐标纸上的x,y区分开

#include <iostream>
using namespace std;

int h,w,tx,ty;
char mmap[55][55] = {0};
int ans = 1;
int dir[4][2] = {
    0,1,
    1,0,
    0,-1,
    -1,0
};


void func(int tx,int ty){
    if(tx < 0 ||tx >= w || ty < 0 || ty >= h){ //越界条件
        return ;
    }
    for(int i = 0; i < 4; i++){ //四个方向
        int x = tx + dir[i][0];
        int y = ty + dir[i][1];
        if(mmap[x][y] == '.'){
            mmap[x][y] = 0;
            ans++;
            func(x,y);
        }
    }

}


int main(){
    cin >> h >>w;
    for(int i = 0; i < w; i++){
        for(int j = 0; j < h; j++){
            cin >> mmap[i][j];
            if(mmap[i][j] == '@'){
                tx = i;
                ty = j;
            }
        }
    }
    func(tx,ty);
    cout << ans << endl;
    return 0;
}

上述题目的解法一般用在求图中黑色的数量,波数等问题。

题目描述
​ 给出 n 件物品,每个物品有一个体积 Vi,从中取出若干件物品能够组成的不同的体积和有多少种可能。例如,n=3 , Vi={1,3,4},那么输出 6 种不同的体积和为 1,3,4,5,7,8。

输入
​ 第一行一个正整数 n。(n≤20)
​ 第二行 n 个整数,表示 Vi。(1≤Vi≤50)

输出
​ 输出一个整数,表示不同体积的组合数。

样例输入
3
1 3 4

样例输出
6

数据规模与约定
​ 时间限制:1 s
​ 内存限制:256 M
​ 100% 的数据保证 n≤20

#include <iostream>
using namespace std;
int n,num[25],ans = 0;
int check[1005] = {1};

void func(int s,int sum){//从s开始选数字,和为sum
    if(check[sum] == 0){
        check[sum] = 1;
        ans++;
    }
    for(int i = s; i <= n; i++){
        sum += num[i];
        func(i + 1, sum);
        sum -= num[i]; //回溯
    }
}

int main(){
    cin >> n;
    for(int i = 0; i < n; i++){
        cin >> num[i];
    }
    func(0,0); 
    cout << ans;
}

DFS可以解决集合问题

题目描述
​ 有很多人在门口排队,每个人将会被发到一个有效的通行密码作为门票。一个有效的密码由 L 个小写字母组成,至少有一个元音 (a,e,i,o,u)和两个辅音,并且是按字母表顺序出现的,例如 abc 是有效的,而 cba 不是。
​ 现在给定一个期望长度 L 和 C 个小写字母,输出所有有效密码。

输入
​ 第一行两个正整数 L,C。(3≤L≤15,C≤26)
​ 接下来一行输入 C个小写字母。

输出
​ 按照字母表顺序输出所有密码,一行一个,若密码超过 2500025000 时,只输出前 2500025000 个密码。

样例输入
4 6
a t c i s w

样例输出
acis
acit
aciw
acst
acsw
actw
aist
aisw
aitw
astw
cist
cisw
citw
istw

数据规模与约定
​ 时间限制:1 s
内存限制:256 M
​ 100% 的数据保证 3≤L≤15,C≤26

#include <iostream>
#include <algorithm>
using namespace std;
int L,C;
char num[26];
char ans[20];
int cnt = 0;
int fu,yuan,num2;

int func(int s, int left){ //从s开始还剩left个
    if(left == 0){ 
        if(yuan >= 1 && fu >= 2){
            for(int i = 0; i < L; i++){
                cout << ans[i];
            }
        
            cout << endl;
            num2++;
            if(num2 == 25000){
                return -1;
            }
        }
    }
    for(int i = s; i < C; i++){
        ans[cnt++] = num[i];
        int f = 0;
        if(num[i] == 'a' || num[i] == 'e' || num[i] == 'i' || num[i] == 'o' || num[i] == 'u'){ 
            yuan++;
            f = 1;
        }else{
            fu++;
        }
        if(func(i+1,left-1) == -1){
            return -1;
        }
        if(f == 1){ //回溯
            yuan--;
        }else{
            fu--;
        }
        cnt--;
    }
    return 0;
}

int main(){
    cin >> L >> C;
    for(int i = 0; i < C; i++){
        cin >> num[i];
    }
    sort(num,num+C);
    func(0,L);
}

题目描述
​ 读入一个用邻接矩阵存储的无向图,输出它的深度优先遍历序列。(以 1为起点,按照编号越小权值越大的规则)

输入
​ 第一行一个正整数 NN,表示节点个数。(5≤N≤20)
​ 接下来输入一个邻接矩阵,a[i,j]=0表示 i,j之间不存在边,=1 说明存在边。

输出
​ 格式参照样例

样例输入
8
0 1 1 0 0 0 0 0
1 0 0 1 1 0 0 0
1 0 0 0 0 0 1 1
0 1 0 0 0 1 0 0
0 1 0 0 0 1 0 0
0 0 0 1 1 0 0 0
0 0 1 0 0 0 0 1
0 0 1 0 0 0 1 0

样例输出
1-2-4-6-5-3-7-8

#include <iostream>
using namespace std;
int n;
int num[25][25],check[25],flag;

void func(int s){
    if(flag == 1){
        cout << '-';
    }    
    flag = 1;
    cout << s;
    for(int i = 1; i <= n; i++){
        if(num[s][i] == 1 && check[i] == 0){
            check[i] = 1;
            func(i);
        }
    }
}

int main(){
    cin >> n;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n ; j++){
            cin >> num[i][j];
        }
    }
    for(int i = 1; i <= n; i++) {
        if(check[i] == 0){
            check[i] = 1;
            func(i);
        }
    }
    return 0;
}

BFS

题目描述
​ 小明刚刚参加完期中考试,“这次又能得班级第一了”,他沾沾自喜,想起之前一直努力学习的自己,他决定去西城红场看个电影放松一下。现在小明想从学校走到电影院,因为市政大力修路和挖地铁,有些道路不允许步行,请判断小明能否走到电影院(只能朝上下左右四个方向行走),如果能到,则输出最短步数,如果不能到,则输出 No.

输入
​ 第 1 行两个数 n 和 m 表示地图有 n 行 m 列 2≤n,m≤500 第 2 行至第 n+1 行为地图,其中 s 表示学校 g表示电影院​ . 为步行可以通过的点 # 为步行不可通过的点

输出
​ 能走到电影院输出最少步数​ 不能走到电影院输出 No

样例输入
4 4
…s
…##

.g…

样例输出
5

数据规模与约定
​ 时间限制:1 s
内存限制:256 M
100% 的数据保证 2≤n,m≤500

#include <iostream>
#include <queue>
using namespace std;

char mmap[505][505];
int n,m,sx,sy;
int dir[4][2]={
    0,1,
    1,0,
    -1,0,
    0,-1
};
struct Node{
    int x,y,cnt;
};
queue<Node> que;
int main(){
    cin >> n >> m;
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            cin >> mmap[i][j];
            if(mmap[i][j] == 's'){
                Node node;
                node.x= i;
                node.y = j;
                node.cnt = 0;
                que.push(node);
            }
        }
    }
    while(!que.empty()){
        Node temp = que.front();
        que.pop();
        for(int i = 0; i < 4; i++){
            int tx = temp.x + dir[i][0];
            int ty = temp.y + dir[i][1];
            if(tx < 0 || ty < 0 || tx >= n || ty >= m){
                continue;
            }
            if(mmap[tx][ty] == 'g'){
                cout << temp.cnt + 1 << endl;
                return 0;
            }
            if(mmap[tx][ty] == '.'){
                mmap[tx][ty] = 0;
                que.push({tx,ty,temp.cnt + 1});
            }
        }

    }
    cout << "No" << endl;
    return 0;
}
发布了46 篇原创文章 · 获赞 64 · 访问量 8777

猜你喜欢

转载自blog.csdn.net/qq_43799957/article/details/105355752