源内容
在一个 7×7 的网格中,从左上角到左下角共有 88418 条路径。每条路径对应一个由 48 个字符组成的描述,包含字符 D(下)、U(上)、L(左)和 R(右)。现在给你一个路径描述,其中可能包含字符 ?(代表任意方向)。我们的任务是计算符合该描述的路径数量。
示例
> 输入: ??????R??????U??????????????????????????LD????D?
>
>
>
> 输出: 201
>
>
>
> 解释: 给定描述下有 201 条可能的路径。
使用深度优先搜索(DFS)的方法
> 核心思路是使用 DFS 算法。如果字符串中的当前字符是‘?’,我们就尝试所有四个方向;否则,我们就按照给定的方向(L, R, U, D)移动。
>
> 优化代码的剪枝/终止搜索策略:
>
> 如果我们无法上下移动,但可以左右移动,或者无法左右移动,但可以上下移动,这种情况下网格会被分割成两部分。显然,我们无法访问到网格的所有部分,因此可以终止搜索。以下这四种情况也会导致部分网格未被访问,因此搜索也需要终止。
>
>
>
> – 如果右上对角线格子已访问,且上方和右方的格子未访问。
> – 如果右下对角线格子已访问,且下方和右方的格子未访问。
> – 如果左上对角线格子已访问,且上方和左方的格子未访问。
> – 如果左下对角线格子已访问,且下方和左方的格子未访问。
分步算法:
- 定义一个函数 INLINECODE370b1d47,它接受当前位置 INLINECODEc699f361 和路径描述字符串中的当前位置
pos作为参数。 - 基础情况 返回 1:
– 如果字符串中的所有字符都已处理完毕,且当前位置是左下角格子,则返回 1(表示找到一条有效路径),否则返回 0。
- 基础情况 返回 0(剪枝条件):
– 如果当前格子已经被访问过。
– 如果在处理完所有字符之前,已经到达了左下角(这意味着路径过短,无法填满网格)。
– 如果当前状态是:上下格子未访问,且左右格子已访问(形成横向阻断,无法继续填满网格)。
– 如果当前状态是:左右格子未访问,且上下格子已访问(形成纵向阻断,无法继续填满网格)。
– 如果当前状态是:右上对角线格子已访问,且上方和右方的格子未访问(形成死角,导致右上角区域无法被访问)。
– 如果当前状态是:右下对角线格子已访问,且下方和右方的格子未访问。
– 如果当前状态是:左上对角线格子已访问,且上方和左方的格子未访问。
– 如果当前状态是:左下对角线格子已访问,且下方和左方的格子未访问。
- 将当前格子标记为已访问。
- 初始化一个变量来存储路径数量。
- 检查字符串中的当前字符是否为‘?’。如果是,尝试所有四个方向(递归调用)。
- 检查字符串中的当前字符是否为方向指令(L, R, U, D)。如果是,向该方向移动。
- 回溯:取消当前格子的访问标记(以便其他路径可以使用该格子)。
- 返回路径的数量。
下面是这种方法的实现代码:
C++
“
// C++ 代码
#include
using namespace std;
// 用于检查坐标在网格中是否有效的宏
#define isValid(a) (a >= 0 && a < 7 ? 1 : 0)
// 方向常量
#define right 0
#define left 1
#define down 2
#define up 3
// 右、左、下、上的方向向量
int dx[4] = { 0, 0, 1, -1 };
int dy[4] = { 1, -1, 0, 0 };
// 路径描述字符串
string str;
int vis[7][7];
// 计算符合描述的路径数量的函数
int countPaths(int x, int y, int pos)
{
// 如果我们已经处理了字符串中的所有字符,
// 并且我们位于左下角,则返回 1
if (pos == (int)str.length())
return (x == 6 && y == 0);
// 如果在处理完所有字符之前到达了左下角,
// 则返回 0
if (x == 6 && y == 0)
return 0;
// 如果当前单元格已经被访问过,则返回 0
if (vis[x][y])
return 0;
// 数组用于跟踪相邻单元格的访问状态
vector visited(4, -1);
for (int k = 0; k < 4; k++)
if (isValid(x + dx[k]) && isValid(y + dy[k]))
visited[k] = vis[x + dx[k]][y + dy[k]];
// 如果我们处于上下方格未访问、
// 且左右方格已访问的位置,返回 0
if (!visited[down] && !visited[up] && visited[right]
&& visited[left])
return 0;
// 如果我们处于左右方格未访问、
// 且上下方格已访问的位置,返回 0
if (!visited[right] && !visited[left] && visited[down]
&& visited[up])
return 0;
// 如果我们处于一个位置 s