p1002题解
题目链接:https://www.luogu.com.cn/problem/P1002
题目简述:卒从棋盘左上角 (0,0) 走到右下角 (n,m),只能向下或向右走。
棋盘上有一只马,马所在位置及其能跳到的点(共9个)是障碍,不能经过。
求从起点到终点的路径总数
思路分析:这道题求方案数,还是棋盘类型,可以想到用dfs写(数据范围小,能过),就算数据大一点,也可以用记忆法搜索的方法来优化,这里给出两种方案:dfs+记忆化搜索,dp
为什么会想到动态规划呢?(超强注意力)注意到,卒只能向下或者向右,因此到达棋盘上每个格子的方案数=左方格子方案数+上方格子方案数
点击查看记忆化搜索代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, m, hx, hy;
bool block[25][25];
ll memo[25][25];
// 马的控制点偏移
int dx[] = {0, 2, 2, 1, 1, -2, -2, -1, -1};
int dy[] = {0, 1, -1, 2, -2, 1, -1, 2, -2};
ll dfs(int i, int j) {
// 越界或在马的控制点
if (i < 0 || j < 0 || i > n || j > m || block[i][j])
return 0;
// 起点
if (i == 0 && j == 0)
return 1;
// 已计算过
if (memo[i][j] != -1)
return memo[i][j];
// 递归求解
return memo[i][j] = dfs(i - 1, j) + dfs(i, j - 1);
}
int main() {
cin >> n >> m >> hx >> hy;
// 标记马的控制点
for (int k = 0; k < 9; k++) {
int nx = hx + dx[k];
int ny = hy + dy[k];
if (nx >= 0 && nx <= n && ny >= 0 && ny <= m)
block[nx][ny] = true;
}
memset(memo, -1, sizeof(memo));
cout << dfs(n, m) << endl;
return 0;
}
点击查看动态规划代码
#include <iostream>
using namespace std;
int main() {
int n, m, x, y;
cin >> n >> m >> x >> y;
// 马的控制点偏移量
int dx[] = {0, 2, 2, 1, 1, -2, -2, -1, -1};
int dy[] = {0, 1, -1, 2, -2, 1, -1, 2, -2};
// 标记障碍
bool block[25][25] = {false};
for (int k = 0; k < 9; k++) {
int nx = x + dx[k];
int ny = y + dy[k];
if (nx >= 0 && nx <= n && ny >= 0 && ny <= m)
block[nx][ny] = true;
}
// DP数组
long long dp[25][25] = {0};
dp[0][0] = 1;
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= m; j++) {
if (block[i][j]) continue; // 跳过障碍
if (i > 0) dp[i][j] += dp[i - 1][j];
if (j > 0) dp[i][j] += dp[i][j - 1];
}
}
cout << dp[n][m] << endl;
return 0;
}
记忆化搜索
讲的特别好!我也是看这个系列视频入门的

浙公网安备 33010602011771号