P1002 [NOIP 2002 普及组] 过河卒——动态规划
题目描述
棋盘上
棋盘用坐标表示,
现在要求你计算出卒从
输入格式
一行四个正整数,分别表示
输出格式
一个整数,表示所有的路径条数。
输入输出样例 #1
输入 #1
6 6 3 3
输出 #1
6
说明/提示
对于
【题目来源】
NOIP 2002 普及组第四题
题解
这是一道典型的动态规划问题,关键在于利用动态规划的思想,通过逐步计算从起点到每个点的路径数,并考虑马的控制点不能通过。
解析
- 状态定义:
- 设
dp[i][j]
表示从A(0, 0)
点到(i, j)
点的路径条数。 - 初始状态:
dp[0][0] = 1
,因为起点本身有一条路径(即不移动)。
- 设
- 状态转移方程:
- 对于非马控制点的点
(i, j)
,它可以从上方(i - 1, j)
或左方(i, j - 1)
到达。 - 所以
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
(当i > 0
且j > 0
时)。 - 当
i == 0 && j > 0
时,dp[i][j] = dp[i][j - 1]
,即只能从左方到达。 - 当
j == 0 && i > 0
时,dp[i][j] = dp[i - 1][j]
,即只能从上方到达。
- 对于非马控制点的点
- 马控制点处理:
- 马的控制点及其自身设为不可达,即
dp[i][j] = 0
。 - 马能控制的点包括马自身以及马按 “日” 字走法能到达的点。例如马在
(x, y)
,则马能控制的点有(x + 1, y + 2), (x + 2, y + 1), (x - 1, y + 2), (x - 2, y + 1), (x + 1, y - 2), (x + 2, y - 1), (x - 1, y - 2), (x - 2, y - 1), (x, y)
。
- 马的控制点及其自身设为不可达,即
代码实现(Python)
n, m, x, y = map(int, input().split()) dp = [[0] * (m + 1) for _ in range(n + 1)] # 标记马的控制点 horse_control = [(x, y), (x + 1, y + 2), (x + 2, y + 1), (x - 1, y + 2), (x - 2, y + 1), (x + 1, y - 2), (x + 2, y - 1), (x - 1, y - 2), (x - 2, y - 1)] for i, j in horse_control: if 0 <= i <= n and 0 <= j <= m: dp[i][j] = -1 # 初始化起点 dp[0][0] = 1 if dp[0][0]!= -1 else 0 for i in range(n + 1): for j in range(m + 1): if dp[i][j] == -1: continue if i > 0 and dp[i - 1][j]!= -1: dp[i][j] += dp[i - 1][j] if j > 0 and dp[i][j - 1]!= -1: dp[i][j] += dp[i][j - 1] print(dp[n][m])
代码实现(C++)
#include <iostream> #include <cstring> using namespace std; const int N = 25; long long dp[N][N]; bool horse_control[N][N]; int main() { int n, m, x, y; cin >> n >> m >> x >> y; memset(horse_control, false, sizeof(horse_control)); horse_control[x][y] = true; int dx[] = {1, 2, -1, -2, 1, 2, -1, -2}; int dy[] = {2, 1, 2, 1, -2, -1, -2, -1}; for (int i = 0; i < 8; ++i) { int new_x = x + dx[i]; int new_y = y + dy[i]; if (new_x >= 0 && new_x <= n && new_y >= 0 && new_y <= m) { horse_control[new_x][new_y] = true; } } dp[0][0] = horse_control[0][0]? 0 : 1; for (int i = 0; i <= n; ++i) { for (int j = 0; j <= m; ++j) { if (horse_control[i][j]) { continue; } if (i > 0 &&!horse_control[i - 1][j]) { dp[i][j] += dp[i - 1][j]; } if (j > 0 &&!horse_control[i][j - 1]) { dp[i][j] += dp[i][j - 1]; } } } cout << dp[n][m] << endl; return 0; }
最终答案即为 dp[n][m]
,它表示从 A
点到 B
点的路径条数。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了