P1002 [NOIP 2002 普及组] 过河卒——动态规划

题目描述

棋盘上 A 点有一个过河卒,需要走到目标 B 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 C 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。

棋盘用坐标表示,A(0,0)B(n,m),同样马的位置坐标是需要给出的。

现在要求你计算出卒从 A 点能够到达 B 点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。

输入格式

一行四个正整数,分别表示 B 点坐标和马的坐标。

输出格式

一个整数,表示所有的路径条数。

输入输出样例 #1

输入 #1

6 6 3 3

输出 #1

6

说明/提示

对于 100% 的数据,1n,m200 马的坐标 20

【题目来源】

NOIP 2002 普及组第四题

题解

这是一道典型的动态规划问题,关键在于利用动态规划的思想,通过逐步计算从起点到每个点的路径数,并考虑马的控制点不能通过。

解析

  1. 状态定义:
    • dp[i][j] 表示从 A(0, 0) 点到 (i, j) 点的路径条数。
    • 初始状态:dp[0][0] = 1,因为起点本身有一条路径(即不移动)。
  2. 状态转移方程:
    • 对于非马控制点的点 (i, j),它可以从上方 (i - 1, j) 或左方 (i, j - 1) 到达。
    • 所以 dp[i][j] = dp[i - 1][j] + dp[i][j - 1](当 i > 0j > 0 时)。
    • i == 0 && j > 0 时,dp[i][j] = dp[i][j - 1],即只能从左方到达。
    • j == 0 && i > 0 时,dp[i][j] = dp[i - 1][j],即只能从上方到达。
  3. 马控制点处理:
    • 马的控制点及其自身设为不可达,即 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 点的路径条数。

发布于   xiins  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示