P1002 [NOIP2002 普及组] 过河卒(c++ dp)

文章介绍了一道编程题目,涉及动态规划技巧,计算棋盘上过河卒避开马的路径数,通过状态转移避开马的控制区域。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

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

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

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

输入格式

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

输出格式

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

输入输出样例

输入 

6 6 3 3

输出 

6

说明/提示

对于 100%100% 的数据,1≤𝑛,𝑚≤201≤n,m≤20,0≤0≤ 马的坐标 ≤20≤20。

【题目来源】

NOIP 2002 普及组第四题

 题解

思路

首先这题卒只有向下和向右两个方向走,遇到马能到的位置,不能走

我们会发现如下图,当我们到达(1,1)这个点的时候

可以是(0,0)右走在下 也可以是(0,0)下走向右

在通过(2,1)一样会发现

路线条数为(到达上面个点的条数加上到达左边个点的条数)

因此状态转移方程为graph[i][j] = max(graph[i][j], graph[i - 1][j] + graph[i][j - 1[]);

 这是我一开始的代码

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 30;
long long graph[N][N];
//8个方向的x和y
int dx[] = {-1, -2, -2, -1, 1, 2, 2, 1};
int dy[] = {-2, -1, 1, 2, 2, 1, -1, -2};
int v[N][N];//用来标记马的位置和马会到的位置


int main(){
	int n, m, mx, my;
	cin >> n >> m >> mx >> my;
	
	memset(graph, 0, sizeof graph);
	memset(v, 1, sizeof v);
	//第一个点为1
	graph[0][0] = 1;
	
	v[mx][my] = 0;//马的位置不能走
	for (int i = 0; i < 8; i ++){
		v[mx + dx[i]][my + dy[i]] = 0;//马能到的点不能走
	}
	
	long long  top,left;//越界的用途
	for (int i = 0; i <= n; i ++){
		for (int j = 0; j <= m; j ++){

			if (!v[i][j])//如果是马在的地方就跳过
			continue;
			if(i - 1 < 0) top = 0;//如果越界,说明左边为0
			else top = graph[i - 1][j];

			if (j - 1 < 0) left = 0;//越界上面为0
			else left = graph[i][j - 1];
			
			graph[i][j] = max(graph[i][j], top + left);//找最大值给当前这个点
			
		}
	}
	cout << graph[n][m];
	
	return 0;
} 

会发现 我会花一些其他的东西来防止越界,最后我发现可以整体移动一位,就能够房子越界

 我更新后的代码为下面这个

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 30;
long long graph[N][N];
int dx[] = {-1, -2, -2, -1, 1, 2, 2, 1};
int dy[] = {-2, -1, 1, 2, 2, 1, -1, -2};
int v[N][N];


int main(){
	int n, m, mx, my;
	cin >> n >> m >> mx >> my;

	memset(graph, 0, sizeof graph);
	memset(v, 1, sizeof v);

	graph[1][1] = 1;
	n ++, m ++, mx ++, my ++;//整体移动一位后,上面个左边的边界就不会越界,都是为0
	v[mx][my] = 0;
	for (int i = 0; i < 8; i ++){
		v[mx + dx[i]][my + dy[i]] = 0;
	}
	
	for (int i = 1; i <= n; i ++){
		for (int j = 1; j <= m; j ++){
			if (!v[i][j])
			continue;
			graph[i][j] = max(graph[i][j], graph[i - 1][j] + graph[i][j - 1]);
			
		}
	}
	cout << graph[n][m];
	
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DsirNg

加油努力,千万不要放弃

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值