引言
二维网格,一个起点一个终点,若干个障碍点,其余为空点,要求给出从起点到终点的所有不经过障碍点、不经过重复点、经过所有空点的路径总数。
例题
算法描述
常规的做法是DFS,上下左右四个方向,回溯是否重复访问,并且记录一下经过的空点总数,最后判断一下是否可以计入答案。
改进的做法是,观察到本题的二维网格大小很小,可以状态压缩。状态由两部分组成,一部分为目前已经过的点,另一部分为当前点在哪个坐标。然后根据状态的值记忆化搜索即可。
由于本题的重复的情况并不多,所以改进版做法的实际用时可能更长,但是有必要学习一下状态压缩的写法。
代码实现
class Solution {
public:
int dx[4] = {-1, 0, 1, 0},
dy[4] = {0, -1, 0, 1};
unsigned int st = 0; //状态
int ans = 0;
int n, m, nm;
unordered_map<int, int> sta_val;
int uniquePathsIII(vector<vector<int>>& a) {
function<int(int, int)> get_xy = [=](int x, int y) -> int {
return x * m + y;
};
int stai, staj;
unsigned int full_st;
n = a.size();
m = a[0].size();
full_st = (1 << n * m) - 1;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (a[i][j] == 1) {
stai = i;
staj = j;
st |= 1 << get_xy(i, j);
} else if (a[i][j] == -1) {
st |= 1 << get_xy(i, j);
}
}
}
function<int(int, int, int)> dfs = [&](int x, int y, int st) -> int {
if (a[x][y] == 2) {
if (st == full_st)
return 1;
return 0;
}
int ret = 0;
int p = get_xy(x, y);
int status = (p << n*m) | st;
if (sta_val.count(status)) {
return sta_val[status];
}
for (int i = 0; i < 4; i++) {
int tx, ty;
tx = x + dx[i];
ty = y + dy[i];
if (tx<0 || tx>=n || ty<0 || ty>=m || st>>get_xy(tx, ty)&1 || a[tx][ty]==-1) {
continue;
}
ret += dfs(tx, ty, st|(1<<get_xy(tx, ty)));
}
return sta_val[status] = ret;
};
return dfs(stai, staj, st);
}
};
关键词
力扣 每日一题 不同路径III 980 DFS 记忆化搜索 状态压缩