马拦过河卒(递推)

原题链接[洛谷p1002 马拦过河卒]

题面

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

棋盘用坐标表示,A 点 (0, 0)、B 点 (n,m),同样马的位置坐标是需要给出的。
在这里插入图片描述
现在要求你计算出卒从 A 点能够到达 B 点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。

解析

起初我直接用递归的方法直接一步一步的追溯, 但由于递归本身很耗时间, 因此超时.
于是我开始想怎样可以更快的找到 A (0, 0) 到 B 点的所有路径,.
首先, 我们知道卒的走法只有向下向右, 那么先假设没有马的存在, 从 A(0, 0) 点开始走, 到 (0, 1) 点的路径条数为 1; 到 (1, 0) 点的路径条数也为 1; 那么 到 (1, 1) 的路径有几条呢?
我们知道在到 (1, 1) 的前一步, 卒一定在 (0, 1)(1, 0) 中的其中一个位置, 也就说从 (0, 0)(1, 1) 的路径条数就是到 (0, 1) 和到 (1, 0) 的路径条数之和, 即到 (1,1) 点的路径有 2 条.
由此我们可以继续推出卒到 (n, m) 点的路径条数的递推式为: d[n][m] = d[n - 1][m] +d[n][m - 1].
由此我们可以用 d[i][j] 来储存从 A(0, 0) 点到该点的路径条数.

例子

Input

6 6 3 3

Output

6
图形解析

在这里插入图片描述

以下是我写的代码:

#include <iostream>
#include <algorithm>
using namespace std;
long long ma[30][30], n, m, x, y;//数据结果可能超过 int;
int b[9][2] = {{0, 0}, {-2, -1}, {-1, -2}, {-2, 1}, {-1, 2}, {2, 1}, {1, 2}, {2, -1}, {1, -2}};
		//马控制点相对于马所在位置的距离;
int main() {
	cin >> n >> m >> x >> y;
	x += 1;//加 1 是为了留出一个边界以使 ma[i - 1][j] 和 ma[i][j - 1] 都在数组范围内;
	y += 1;//此时 A 点对应数组 ma[1][1];
	n += 1;
	m += 1;
	ma[1][1] = 1;
	for (int i = 0; i < 9; i++) {
		ma[x + b[i][0]][y + b[i][1]] = -1;//标记马的控制点;
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (ma[i][j] != -1) {//当该点不是马的控制点时, 进行一下操作;
				if (ma[i - 1][j] == -1 || ma[i][j - 1] == -1) {
				//该判断语句是看该点上和左是否是马的控制点;
				//注意卒的左和上最多只有一个是马的控制点, 因此一次性进行判断;
						ma[i][j] += 1;//若马的上和下有马的控制点, 则加 1 以抵消下式加上的负一;
					}
				ma[i][j] += ma[i - 1][j] + ma[i][j - 1];//路径条数的递推公式;
			}	
		}
	}
	cout << ma[n][m] << endl;
	return 0;
} 
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值