C++知识点总结(36-39):深度优先搜索算法综合练习

*本篇文章涉及较多知识点,可以在下面查看对应的教程:
递归基础 / 递归进阶 / 递归练习1 / 递归练习2 / DFS1 / DFS2 / 回溯算法 / DFS3

一、递归

1. 变化的数

有一个数 a a a,想把这个数变成 b b b,为此可以做两种变换:

x x x 变为 2 x 2x 2x
x x x 变为 10 x + 1 10x+1 10x+1
例如:2 -> 4 -> 8 -> 81 -> 162

你需要判断一下,把 a a a 变成 b b b 的是否可能,可能则输出 YES,否则输出 NO

#include <iostream>
using namespace std;

// 递归判断是否存在变换路径
bool transform(int a, int b)
{
    if (a == b) return 1; // 当 a 和 b 相等时,变换成功,返回 true
    if (a > b) return 0; // 当 a 大于 b 时,无法变换,返回 false
    return transform(a*2, b) || transform(a*10+1, b); // 递归进行两种变换判断
}

int main()
{
    int a, b;
    cin >> a >> b;
    cout << (transform(a, b) ? "YES" : "NO"); // 输出是否存在变换路径
    return 0;
}

2. 数字分解

一个正整数,可以分解成多个大于等于 1 1 1 的整数之和的形式,要求这些数字从左向右是递增的(即后一个数小于等于前一个数)。请你求出对于一个整数 n n n,一共有多少种分解方案。

#include <iostream>
using namespace std;

int n;

int f(int n, int maxn)
{
    if (n == 0) return 1;
    int cnt = 0;
    for (int i = 1; i <= maxn && i <= n; i++)
    {
        cnt += f(n-i, i);
    }
    return cnt;
}

int main()
{
    cin >> n;
    cout << f(n, n);
}

二、DFS

1. 八个方向的迷宫

给定一个 n n n m m m 列的迷宫,有些格子可以走,有些有障碍物不能到达。每步可以走到周围 8 8 8 个方向的格子中。请你判断,是否能从左上角走到右下角。如果能走到输出 YES,否则输出 NO

同样地,不撞南墙不回头,记得将偏差值改一下就好了。

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

int n, m; // 迷宫大小
bool flag; // 是否有解 
char Map[25][25]; // 地形图
bool vis[25][25]; // 标记是否走过 
int dx[10] = {-1, -1, -1, 0, 0, 1, 1, 1}; // 八个方向的偏移量 
int dy[10] = {-1, 0, 1, -1, 1, -1, 0, 1}; // 八个方向的偏移量 

void dfs(int x, int y)
{
	// 到终点 
	if (x == n && y == m)
	{
		flag = true;
		return;
	}
	
	// 遍历方向,判断是否满足条件
	for (int i = 0; i < 8; i++)
	{
		int tmpX = x + dx[i];
		int tmpY = y + dy[i];
		
		// 是通路
		if (Map[tmpX][tmpY] == '.')
		{
			// 未到边界
			if (tmpX >= 1 && tmpX <= n && tmpY >= 1 && tmpY <= m) 
			{
				// 未访问
				if (vis[tmpX][tmpY] == false) 
				{
					vis[tmpX][tmpY] = true;
					dfs(tmpX, tmpY);
				}
			}
		}
	}
}

int main()
{
    freopen("map.in", "r", stdin);
    freopen("map.out", "w", stdout);
    
	// 输入
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			cin >> Map[i][j];
		}
	}
	
	// dfs
	vis[1][1] = 1;
	dfs(1, 1);
	
	// 输出	
	cout << (flag ? "YES" : "NO");
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}

2. n 皇后

题目描述

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n n n 皇后问题研究的是如何将 n n n 个皇后放置在 n × n n\times n n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n n n,求出所有不同的 n n n 皇后问题的解决方案。
每一种解法包含一个不同的 n n n 皇后问题的棋子放置方案,该方案中 'Q''.' 分别代表了皇后和空位。

输入描述

仅一行,一个正整数 n n n

输出描述

若干行, n × n n\times n n×n 的棋盘所有的解,每个解用空格隔开

样例1

输入

4

输出

.Q..
...Q
Q...
..Q.

..Q.
Q...
...Q
.Q..

提示

4 ≤ n ≤ 18 4≤n≤18 4n18

思路:这是根据《C++知识点总结(37):回溯算法》中第四节的题目改编而来。我们可以知道,按照题目所描述的方法,我们应该使得:

  • 每一行都只有一个皇后
  • 每一列都只有一个皇后
  • 每一个正对角线都只有一个皇后
  • 每一个负对角线都只有一个皇后
#include <iostream>
using namespace std;

int n;
bool a[20][20];
bool row[20];
bool col[20];
bool zd[40], fd[40];

void dfs(int r)
{
    if (r > n)
    {
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                if (a[i][j])
                {
                    cout << "Q";
                }
                else
                {
                    cout << ".";
                }
            }
            cout << endl;
        }
        cout << endl;
        return;
    }
    
    for (int j = 1; j <= n; j++) // 遍历每个列
    {
        if (!a[r][j] && !row[r] && !col[j] && !zd[r+j] && !fd[r-j+n]) // 是否没有冲突
        {
            a[r][j] = true;
            row[r] = true;
            col[j] = true;
            zd[r+j] = true;
            fd[r-j+n] = true;
            dfs(r+1);
            a[r][j] = false;
            row[r] = false;
            col[j] = false;
            zd[r+j] = false;
            fd[r-j+n] = false;
        }
    }
}

int main()
{
    cin >> n;
    dfs(1);
    return 0;
}

3. 玩具蛇

题目描述

小蓝有一条玩具蛇,一共有 n 2 n^2 n2 节,上面标着数字1至 n 2 n^2 n2,每一节都是一个正方形的形状,相邻的两节可以成直线或者成直角。
小蓝还有一个 n × n n\times n n×n 的方格盒子,用于存放玩具蛇,盒子的方格上依次标着字母共 n 2 n^2 n2 个字母。
小蓝可以折叠自己的玩具蛇放到盒子里面。他发现,有很多种方案可以将玩具蛇放进去。
请帮小蓝计算一下,总共有多少种不同的方案。如果存在玩具蛇的某一节放在了盒子的不同格子里,则认为是不同的方案。

输入描述

一个整数 q q q,表示输入 q q q 组方格盒子。
接下来 q q q 行,每行代表一个 n × n n\times n n×n 的方格盒子。

输出描述

q q q 个整数表示每个方格盒子的方案数。

样例1

输入

2
2
4

输出

8
552

提示

1 ≤ n ≤ 5 1\le n\le5 1n5

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

int q; // 输入的组数
int n; // 盒子的边长
bool vis[10][10]; // 盒子是否被占据
int total; // 方案数量
int dx[5] = {-1, 0, 1, 0};
int dy[5] = {0, 1, 0, -1};

void dfs(int x, int y, int cnt)
{
    if (cnt == n*n)
    {
        total++;
        return;
    }
    
    for (int i = 0; i < 4; i++)
    {
        int tx = x+dx[i];
        int ty = y+dy[i];
        if (tx>=1 && tx<=n && ty>=1 && ty<=n)
        {
            if (vis[tx][ty] == 0)
            {
                vis[tx][ty] = 1;
                dfs(tx, ty, cnt+1);
                vis[tx][ty] = 0;
            }
        }
    }
}

int main()
{
    // 输入
    cin >> q;
    for (int i = 1; i <= q; i++)
    {
        cin >> n;
        total = 0;
        memset(vis, 0, sizeof(vis));
        
        // dfs
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                vis[i][j] = 1;
                dfs(i, j, 1);
                vis[i][j] = 0;
            }
        }
        
        // 输出
        cout << total << endl;
    }
    return 0;
}

4. 深度优先搜索顺序

题目描述

给定一个 n n n m m m 列的迷宫,有些格子可以走,有些有障碍物不能到达。每步可以走到上下左右的格子中。请你输出从左上角(第一行第一列)开始深度优先搜索所有格子的顺序。其中,从一个格子出发,优先出发的顺序为:上、下、左、右,每个格子只遍历一次,即按搜索顺序输出从左上角开始能够搜索到的所有位置。

输入描述

第一行有两个正整数 n n n m m m,表示迷宫的行数和列数。
接下来 n n n 行为输入这个迷宫,每行为一个长度为 m m m 的字符串。第 i i i 行第 j j j 列的字符为 '*' 表示迷宫第 i i i 行第 j j j 列的格子有障碍物,为 '.' 表示没有障碍物。

输出描述

若干行,按遍历顺序在每行输出搜索到的格子。第 x x x 行第 y y y 列的格子以 "(x,y)" 的格式输出。

样例1

输入

3 3
.*.
...
***

输出

(1,1)
(2,1)
(2,2)
(2,3)
(1,3)

提示

1 ≤ n , m ≤ 100 1 \le n, m \le 100 1n,m100

#include <iostream>
using namespace std;

int n, m;
char a[105][105];
bool vis[105][105];
int dx[5] = {-1, 1, 0, 0};
int dy[5] = {0, 0, -1, 1};
int pos = 1;
int ansx[10005];
int ansy[10005];

void dfs(int x, int y)
{
    cout << "(" << x << "," << y << ")\n";
    for (int i = 0; i <= 3; i++)
    {
        int tx = x+dx[i];
        int ty = y+dy[i];
        if (a[tx][ty] == '.')
        {
            if(tx>=1 && tx<=n && ty>=1 && ty<=m)
            {
                if (vis[tx][ty] == 0)
                {
                    vis[tx][ty] = 1;
                    dfs(tx,ty);
                }
            }
        }
    }
}

int main()
{
    // 输入
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            cin >> a[i][j];
        }
    }
    
    // dfs
    vis[1][1] = 1;
    dfs(1, 1);
    return 0;
}

5. 单词消消乐

题目描述

给定一个 n × n n \times n n×n 的字母方阵和一个字符串单词,内可能含有多个这样的单词,单词在方阵中是沿着同一方向连续摆放的,摆放可沿着 8 8 8 个方向的任一方向,同一单词摆放时不再改变单词方向,单词与单词之间可以交叉,因此可能共用字母,输出时,将不是单词的字母用 '*' 代替,以凸显单词。

输入描述

输入文件名word.in。
第一行一个数 n n n,表示字母方阵的大小( 7 ≤ n ≤ 100 7 \le n \le 100 7n100),第二行开始输入 n × n n \times n n×n 的字母方阵,字母间没有空格。
最后一行输入一个字符串单词,单词长度在 1 1 1 15 15 15 之间。

输出描述

输出文件名word.out。
突出显示单词的 n × n n \times n n×n 字母方阵。

样例1

输入

4
abcd
fesh
eawj
qbso
ab

输出

ab**
****
*a**
*b**

提示

题中所有字母均为小写

#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
using namespace std;

int n;
int pos;
char a[120][120];
int dx[10] = {-1, -1, -1, 0, 0, 1, 1, 1};
int dy[10] = {-1, 0, 1, -1, 1, -1, 0, 1};
string s;
int px[120], py[120];
bool vis[120][120];

void dfs(int x, int y, int h)
{
    if (pos == s.length()) // 边界
    {
        for (int i = 0; i < pos; i++)
        {
            vis[px[i]][py[i]] = 1;
        }
        return;
    }
    
    int tx = x + dx[h];
    int ty = y + dy[h];
    if (tx >= 1 && tx <= n && ty >= 1 && ty <= n && a[tx][ty] == s[pos])
    {
        px[pos] = tx;
        py[pos] = ty;
        pos++;
        dfs(tx, ty, h);
    }
}

int main()
{
    freopen("word.in", "r", stdin);
    freopen("word.out", "w", stdout);
    
    // 输入
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            cin >> a[i][j];
        }
    }
    cin >> s;
    
    // 找到开头字符
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (a[i][j] == s[0])
            {
                for (int h = 0; h <= 7; h++)
                {
                    pos = 0;
                    // memset(px, 0, sizeof(px));
                    // memset(py, 0, sizeof(py));
                    px[0] = i;
                    py[0] = j;
                    pos++;
                    dfs(i, j, h);
                }
            }
        }
    }
    
    // 输出
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (vis[i][j])
            {
                cout << a[i][j];
            }
            else
            {
                cout << "*";
            }
        }
        cout << endl;
    }
    
    fclose(stdin);
    fclose(stdout);
    return 0;
}

6. 奇怪的系统

题目描述

原本平静的生活被打破,你被卷入一场神秘的案件中,成为侦探团的一员,由于你自带解谜系统,所以解决案件对你来说小菜一碟,但系统有一个神奇的地方,只有给出满足要求的案件物品,系统才能给出线索,每个案件物品都有线索值,因此组合得到的线索也不一样。
现在你面前有 n n n 个不同线索值的案件物品,系统需要的线索值为 m m m,每给出一组不同的物品组合使线索值总和刚好为 m m m 则可以得到一条新的线索,并且物品不会因为给系统而消失,为了解开这个谜团,你需要选择合适数量与线索值的案件物品给系统,以此得到不同的线索,你一共能够得到多少条线索呢?

输入描述

第一行输入 n n n m m m,第二行一共 n n n 个数字,表示每个案件物品的线索值 a i a_i ai

输出描述

输出能够得到的线索条数。

样例1

输入

3 40 
20 20 20

输出

3

提示

【样例解释】
一共 3 3 3 个物品,线索值分别为 20 , 20 , 20 20,20,20 20,20,20
系统需要的线索值为 40 40 40,则可以 1 , 2 1,2 1,2 组合, 1 , 3 1,3 1,3 组合, 2 , 3 2,3 2,3 组合刚好都为 40 40 40 1 , 2 , 3 1,2,3 1,2,3 组合超过 40 40 40 不符合,所以得到 3 3 3 条线索。
【数据范围】
0 < m ≤ 100 , 1 ≤ n ≤ 20 , a i ≤ m 0<m\le100,1\le n\le20,a_i\le m 0<m1001n20aim

#include <iostream>
using namespace std;

int n, m;
int cnt;
int a[25];
bool used[25];

// 判断选择的数字之和是否等于预设值
bool check()
{
	// 求和 
	int sum = 0;
	for (int i = 1; i <= n; i++)
	{
		if (used[i])
		{
			sum += a[i];
		}
	}
	
	// 判断是否等于预设值
	if (sum == m)
	{
	    return true;
	}
	return false;
}

// pos: 当前位置
// cnt: 选的数字个数 
void dfs(int pos)
{
	if (pos > n) // 边界
	{
		if (check()) // 题目条件
		{
			cnt++;
		}
		return;
	}
	dfs(pos+1); // 不选
	used[pos] = 1; // 标记
	dfs(pos+1); // 选 
	used[pos] = 0; // 回溯
}

int main()
{
	// 输入 
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
	}
	
	// dfs
	dfs(1);
	
	// 输出
	cout << cnt; 
	return 0;
}

7. [USACO23JAN] Air Cownditioning II B

参观一下某谷吧。

#include <iostream>
using namespace std;

int n, m, k;
int ans = 1e9;
int cw[105], s[25], t[25], c[25], a[25], b[25], p[25], v[25];

bool check() // 是否满足条件
{
	for(int i = 1; i <= k; i++)
	{
		if (cw[i] > 0)
		{
		    return false;
		}
	}
	return true;
}

void dfs(int pos, int s)
{
	if (pos > m)
	{
		if (check())
		{
		    ans = min(ans, s);//满足条件,更新答案
		}
		return;
	}
	dfs(pos+1, s); // 不选
	// 标记
	for(int i = a[pos]; i <= b[pos]; i++)
	    cw[i] -= p[pos];
	
	dfs(pos+1, s+v[pos]); // 选
	// 回溯
	for(int i = a[pos]; i <= b[pos]; i++)
	    cw[i] += p[pos];
}

int main()
{
    // 输入
	cin >> n >> m;
	for(int i = 1; i <= n; i++)
	{
		cin >> s[i] >> t[i] >> c[i];
		k = max(k, t[i]);
		for (int j = s[i]; j <= t[i]; j++)
		{
		    cw[j] += c[i]; //事先处理
		}
	}
	for (int i = 1; i <= m; i++)
	    cin >> a[i] >> b[i] >> p[i] >> v[i];
	
	// dfs
	dfs(1, 0);
	
	// 输出
	cout << ans;
	return 0;
}

三、排列组合

选择同学

题目描述

今有 n n n 位同学,可以从中选出任意名同学参加合唱。
请输出所有可能的选择方案。

输入描述

仅一行,一个正整数 n n n

输出描述

若干行,每行表示一个选择方案。
每一种选择方案用一个字符串表示,其中第 i i i 位为 Y Y Y 则表示第 i i i 名同学参加合唱;为 N N N 则表示不参加。

样例1

输入

3

输出

NNN
NNY
NYN
NYY
YNN
YNY
YYN
YYY

提示

1 ≤ n ≤ 10 1≤n≤10 1n10

思路:这是非常典型的一道回溯题,与《C++知识点总结(37):回溯算法》中第二节的第一小节比较类似。因为这道题目只有 Y Y Y N N N 两种可能,所以在深度优先搜索的时候,我们只需要用两个递归就可以,不需要 for 循环了。

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;

int n;
string s;

void dfs(int pos, string s)
{
    if (pos > n)
    {
        cout << s << endl;
        return;
    }
    dfs(pos+1, s+'N');
    dfs(pos+1, s+'Y');
}

int main()
{
    cin >> n;
    dfs(1, s);
    return 0;
}

四、剪枝优化

1. 走迷宫

题目描述

在一个神秘的迷宫中,有一个勇敢的冒险家,他的目标是从起点 ( 1 , 1 ) (1,1) (1,1) 走到终点 ( n , n ) (n,n) (n,n)。但是,这个迷宫并不是那么容易通过的,有些地方是可以走的,有些地方是恶龙所在的区域。为了成功通过迷宫,冒险家必须遵循以下规则:

  1. 只能向下、右两个方向移动;
  2. 在移动过程中,可以至多转向 k k k 次。
    如果一条路线中冒险家经过了某个方格而另一条路线中没有,则认为这两条路线不同。
    现在,你需要帮助这位勇敢的冒险家,计算他从起点到终点的方案数。

输入描述

输入文件名maze.in。
第一行包含三个整数 n , k , m n,k,m n,k,m,表示矩阵的大小,转向次数和障碍物的数量。
接下来 m m m 行,每行包含两个整数 x x x y y y,表示第 x x x 行第 y y y 列是障碍物。

输出描述

输出文件名maze.out。
输出一个整数,表示从起点到终点的方案数,方案数可能为 0 0 0那就算给恶龙饱餐一顿了 )。

样例1

输入

5 2 2
2 2
3 4

输出

4

提示

1 ≤ n ≤ 50 1 \leq n \leq 50 1n50
1 ≤ k ≤ 5 1 \leq k \leq 5 1k5
1 ≤ m ≤ 100 1 \leq m \leq 100 1m100

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int n, k, m;
int cnt;
bool a[60][60];
int dx[5] = {0, 1};
int dy[5] = {1, 0};

void dfs(int x, int y, int turn, int direc)
{
	if (x == n && y == n) // 到达终点 
	{
		if (turn <= k)
		{
			cnt++;
		}
		return;
	}
	
	// 剪枝 
	if (turn > k)
	{
	    return;
	}
	if (turn == k)
	{
	    if (x != n && y != n)
	    {
	        return;
	    }
	}
	
	// 递归 
	for (int i = 0; i <= 1; i++)
	{
		int tx = x + dx[i];
		int ty = y + dy[i];
		
		// 是通路
		if (a[tx][ty] == 1)
		{
			// 未到边界
			if (tx >= 1 && tx <= n && ty >= 1 && ty <= n) 
			{
				// 是否转弯 
				if (i != direc && direc != -1)
				{
					dfs(tx, ty, turn+1, i);
				}
				else
				{
					dfs(tx, ty, turn, i);
				}
			}
		}
	}
}

int main()
{
    freopen("maze.in", "r", stdin);
    freopen("maze.out", "w", stdout);
    
    // 初始化迷宫(默认都是通路)
    memset(a, 1, sizeof(a));
    
	// 输入
	cin >> n >> k >> m;
	for (int i = 1; i <= m; i++)
	{
	    int x, y;
	    cin >> x >> y;
		a[x][y] = 0;
	}
	
	// dfs
	dfs(1, 1, 0, -1);
	cout << cnt;
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}

2. 危险的工作

题目描述

在一个神秘的岛屿上,有 N N N 个勇士需要分担 N N N 个危险的工作。每个勇士都有自己的特长,可以担任其中一项工作。每个工作都有一个危险值,代表完成这项工作的风险程度。每个勇士担任工作时,会承担该工作的危险值。现在,你需要为这些勇士分配工作,使得每个勇士承担的危险值之和最小。

输入描述

第一行输入一个整数 N N N,代表勇士的数量。
接下来 N N N 行,每行输入 N N N 个整数,第 i i i 行的 N N N 个数字分别代表第 i i i 个勇士担任 1 − N 1-N 1N 项工作的危险值,用空格隔开。

输出描述

输出一个整数,代表每个勇士承担的危险值之和的最小值。

样例1

输入

3
1 2 3
4 5 6
7 8 9

输出

15

提示

1 ≤ N ≤ 11 1 \le N \le 11 1N11
1 ≤ 1 \le 1 危险值 ≤ 100 \le 100 100

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

int n;
int d[20][20];
int mind = 1e8;
int a[20];
bool vis[20];

void dfs(int pos, int total)
{
    if (pos > n) // 边界
    {
        mind = min(mind, total);
        return;
    }

    for (int i = 1; i <= n; i++)
    {
        if (!vis[i]) // 检查位置是否被占用
        {
            vis[i] = true;
            a[pos] = i; // 标记
            int new_total = total + d[pos][i];
            if (new_total <= mind) // 剪枝
                dfs(pos + 1, new_total); // 递归下一个位置
            a[pos] = -1; // 回溯
            vis[i] = false;
        }
    }
}

int main()
{
    // 初始化
    memset(a, -1, sizeof(a));
    memset(vis, false, sizeof(vis));
    
    // 输入
    cin >> n;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            cin >> d[i][j];
    
    // dfs
    dfs(1, 0);
    
    // 输出
    cout << mind;
    return 0;
}

3. 规定时间走迷宫

第一行给定迷宫的大小 n , m n,m n,m 和规定时间 t t t,表示有一个 n × m n\times m n×m 的迷宫,起点到终点正好是规定时间(每向某个方向走一格,就算 1 s 1s 1s)。
接下来 n n n 行每行 m m m 个空格隔开的字符,'.' 代表空地,'*' 代表障碍。
最后一行给定初始位置和终点位置 s x , s y , e x , e y sx,sy,ex,ey sx,sy,ex,ey
求你求出符合规定时间的路径数。
数据范围: 1 ≤ n , m ≤ 100 1\le n,m \le 100 1n,m100

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

int n, m, t, sx, sy, ex, ey, cnt;
char a[105][105];
bool vis[105][105];
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};

void dfs(int x, int y, int l)
{
    // 剪枝
    if (abs(ex-x)+abs(ey-y) > t-l || l>t)
        return;
    
    // 边界
    if (x==ex && y==ey && l==t)
    {
        cnt++;
        return;
    }
    for (int i = 0; i <= 3; i++) 
    {
        int nx = x+dx[i];
        int ny = y+dy[i];
        if (nx>=0 && nx<=n && ny>=0 && ny<=m) // 未到边界
        {
            if (vis[nx][ny]==0 && a[nx][ny]=='.') // 未访问、是空地
            {
                vis[nx][ny] == 1;
                dfs(nx, ny, l+1);
                vis[nx][ny] == 0;
            }
        }
    }
}

int main()
{
    // 输入
    cin >> n >> m >> t;
    for (int i = 1; i <= n; i++) 
    {
        for (int j = 1; j <= m; j++) 
        {
            cin >> a[i][j];
        }
    }
    cin >> sx >> sy >> ex >> ey;
    
    // dfs
    dfs(sx, sy, 0);
    
    // 输出
    cout << cnt;
    return 0;
}
  • 8
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值