小白的DFS算法学习历程(不定期更新)

  1. 迷宫算法(基础)

定义一个二维数组:

int maze[5][5] = {

0, 1, 0, 0, 0,

0, 1, 0, 1, 0,

0, 0, 0, 0, 0,

0, 1, 1, 1, 0,

0, 0, 0, 1, 0,

};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

输入

一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。

输出

左上角到右下角的最短路径,格式如样例所示。

样例输入 复制
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
样例输出 复制
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)
参考代码(并非本题标准答案,但有重要参考价值):
//迷宫问题的dfs算法  默认以矩形左下角点建立xOy坐标系
#include<bits/stdc++.h>
using namespace std;
int min_step=99999;//代表最小步数
int arr[100][100];//遍历数组,0代表不可遍历,1代表可遍历
int visit[100][100];//访问标记数组,0代表未访问,1代表已经访问

//深度有限搜索算法,作用是将min_step改成最合理的最短路径值

void dfs(int a,int b,int p,int q,int step){
    if(a==p&&b==q)//对应找到终点的一条路径,如果成功找到的情况
    {
        if(step<min_step){
            min_step=step;
        }
        return;//回溯,寻找下一个可能的最优解
    }
    if(arr[a][b+1]==1&&visit[a][b+1]==0){//设目前已经在位置(a,b)中,接下来进行dfs遍历,这是向上方向遍历
    visit[a][b+1]==1;
    dfs(a,b+1,p,q,step+1);
    visit[a][b+1]=0;//这一步需要认真理解,因为深度搜索到底完成后,需要把这条路径清零,从上一个分支结点开始继续深度搜索
    }
    if(arr[a+1][b]==1&&visit[a+1][b]==0){
        visit[a+1][b]=1;
        dfs(a+1,b,p,q,step+1);
        visit[a+1][b]=0;
    }
        if(arr[a-1][b]==1&&visit[a-1][b]==0){
        visit[a-1][b]=1;
        dfs(a-1,b,p,q,step+1);
        visit[a-1][b]=0;
    }
        if(arr[a][b-1]==1&&visit[a][b-1]==0){
        visit[a][b-1]=1;
        dfs(a,b-1,p,q,step+1);
        visit[a][b-1]=0;
    }
}
int main(){
    int m,n;
    cin>>m>>n;//构造出迷宫函数的行与列
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>arr[i][j];
        }
    }
    int start_x,start_y,final_x,final_y;//初始值与终点值
    cin>>start_x>>start_y>>final_x>>final_y;
    dfs(start_x,start_y,final_x,final_y,0);
    cout<<min_step<<endl;
}
思考与改进:四次dfs方向遍历显得写代码的过程有点繁琐,可以通过定义两个方向向量数组,从而在一个for循环中实现四个方向的遍历

改进后的dfs部分代码:

//迷宫问题的dfs算法  默认以矩形左下角点建立xOy坐标系
#include<bits/stdc++.h>
using namespace std;
int min_step=99999;//代表最小步数
int arr[100][100];//遍历数组,0代表不可遍历,1代表可遍历
int visit[100][100];//访问标记数组,0代表未访问,1代表已经访问
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};//这里一定要注意两个方向向量的对应组合能够包括所有dfs方向遍历
//深度有限搜索算法,作用是将min_step改成最合理的最短路径值

void dfs(int a,int b,int p,int q,int step){
    if(a==p&&b==q)//对应找到终点的一条路径,如果成功找到的情况
    {
        if(step<min_step){
            min_step=step;
        }
        return;//回溯,寻找下一个可能的最优解
    }
    for(int i=0;i<4;i++){
        if(arr[a+dx[i]][b+dy[i]]==1&&visit[a+dx[i]][b+dy[i]]==0){//设目前已经在位置(a,b)中,接下来进行dfs遍历,这是向上方向遍历
            visit[a+dx[i]][b+dy[i]]==1;
            dfs(a+dx[i],b+dy[i],p,q,step+1);
            visit[a+dx[i]][b+dy[i]]=0;//这一步需要认真理解,因为深度搜索到底完成后,需要把这条路径清零,从上一个分支结点开始继续深度搜索
        }
    }

}
  1. 正方形

题目描述

有n个木棒,需要用上所有木棒,围成一个正方形,如果可以围成正方形,则输出"yes", 否则输出"no"。

输入

第一行输入一个整数T表示样例个数。

对于每个样例,第一行输入一个整数N表示木棍的个数,第二行输入N个数字表示木棒的长度。

输出

对于每个样例,如果可以则输出"yes", 否则输出"no"。

样例输入 复制
3 
4 
1 1 1 1 
5 
10 20 30 40 50 
8 
1 7 2 6 4 4 3 5
样例输出 复制
yes
no
yes
提示

N <= 20

3、素数环问题(prime circle)

A ring is compose of n circles as shown in diagram. Put natural number 1, 2, ..., n into each circle separately, and the sum of numbers in two adjacent circles should be a prime.

Note: the number of first circle should always be 1.

输入

n (0 < n < 20).

(multi test case)

输出

The output format is shown as sample below. Each row represents a series of circle numbers in the ring beginning from 1 clockwisely and anticlockwisely. The order of numbers must satisfy the above requirements. Print solutions in lexicographical order.

You are to write a program that completes above process.

Print a blank line after each case.

样例输入 复制
6
8
样例输出 复制
Case 1:
1 4 3 2 5 6
1 6 5 2 3 4

Case 2:
1 2 3 8 5 6 7 4
1 2 5 8 3 4 7 6
1 4 7 6 5 8 3 2
1 6 7 4 3 8 5 2

4、棋盘问题

题目描述

在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。

输入

输入含有多组测试数据。

每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n

当为-1 -1时表示输入结束。

随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。

输出

对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。

样例输入 复制
2 1
#.
.#
4 4
...#
..#.
.#..
#...
-1 -1
样例输出 复制
2
1

5、Find a way(KFCer)

Pass a year learning in Hangzhou, yifenfei arrival hometown Ningbo at finally. Leave Ningbo one year, yifenfei have many people to meet. Especially a good friend Merceki.

Yifenfei’s home is at the countryside, but Merceki’s home is in the center of city. So yifenfei made arrangements with Merceki to meet at a KFC. There are many KFC in Ningbo, they want to choose one that let the total time to it be most smallest.

Now give you a Ningbo map, Both yifenfei and Merceki can move up, down ,left, right to the adjacent road by cost 11 minutes.

输入

The input contains multiple test cases.

Each test case include, first two integers n, m. (2<=n,m<=200).

Next n lines, each line included m character.

‘Y’ express yifenfei initial position.

‘M’ express Merceki initial position.

‘#’ forbid road;

‘.’ Road.

‘@’ KCF

输出

For each test case output the minimum total time that both yifenfei and Merceki to arrival one of KFC.You may sure there is always have a KFC that can let them meet.

样例输入 复制
4 4
Y.#@
....
.#..
@..M
4 4
Y.#@
....
.#..
@#.M
5 5
Y..@.
.#...
.#...
@..M.
#...#
样例输出 复制
66
88
66

6、🐎的遍历(吗的)

有一个n*m的棋盘(1<n,m<=400),在某个点上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步

输入

一行四个数据,棋盘的大小和马的坐标

输出

一个n*m的矩阵,同一行元素之间用空格分离。代表马到达某个点最少要走几步。不能到达则输出-1。

样例输入 复制
3 3 1 1
样例输出 复制
0 3 2
3 -1 1
2 1 4

7、how many cells

题目描述

一矩形阵列由数字 0 到 9 组成,数字 1 到 9 代表细胞,细胞的定义为沿细胞数字上下左右若还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。

输入

第一行两个整数代表矩阵大小 n 和 m。 接下来 n 行,每行一个长度为 m 的只含字符 0 到 9 的字符串,代表这个n×m 的矩阵。

输出

一行一个整数代表细胞个数。

样例输入 复制
4 10
0234500067
1034560500
2045600671
0000000089
样例输出 复制
4
提示

0 < m, n <= 400

8、迷宫again

题目描述

有一个仅由数字0与1组成的n×n格迷宫。若你位于一格0上,那么你可以移动到相邻4格中的某一格1上,同样若你位于一格1上,那么你可以移动到相邻4格中的某一格0上。 你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。

输入

第1行为两个正整数n,m。 下面n行,每行n个字符,字符只可能是0或者1,字符之间没有空格。

接下来m行,每行2个用空格分隔的正整数i,j,对应了迷宫中第i行第j列的一个格子,询问从这一格开始能移动到多少格。

输出

m行,对于每个询问输出相应答案。

样例输入 复制
2 2
01
10
1 1
2 2
样例输出 复制
4
4
提示

n <= 400

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值