P1002 过河卒

题目描述

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

棋盘用坐标表示,A点(0, 0)、B点(n, m)(n, m为不超过20的整数),同样马的位置坐标是需要给出的。

在这里插入图片描述

import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in); 
		int x = in.nextInt(),y = in.nextInt(),x1 = in.nextInt(),y1 = in.nextInt();
		long[][] a = new long[25][25];
		int[][] g = new int[25][25];
		g[x1][y1] = 1;
		//记录 这8 个if 是将所有被马控制 点标记为1
		if (x1 >1 && y1 > 0) {
			g[x1-2][y1-1] = 1;
		}
		if (x1 >0  && y1 > 1) {
			g[x1-1][y1-2] = 1;
		}
		if (x1 > 1 && y1 < 20) {
			g[x1-2][y1+1]  =1;
		}
		if (x1 > 0 && y1 < 19) {
			g[x1-1][y1+2] = 1;
		}
		if (x1 < 20 && y1 > 1) {
			g[x1+1][y1-2] = 1;
		}
		if (x1 < 19 && y1 > 0) {
			g[x1+2][y1-1] = 1;
		}
		if (x1 < 20 && y1 < 19) {
			g[x1+1][y1+2] = 1;
		}
		if (x1 < 19 && y1 < 20) {
			g[x1+2][y1+1] = 1;
		}
		for (int i = 0; i <= x; i++) {
			for (int j = 0; j <= y; j++) {
				if (g[i][j] == 0) { // 二维表的初始值都为0,如果控制点的位置为1,那么这个格子就为0 ,也就是继续执行。这个格子后面的格子的最后一步只能向右或下到达,这个格子被占了的话,那么从这个格子到后面格子的路径数位0,只能看右边格子的上面格子数的路径。
					if (i == 0 && j == 0) {
						a[0][0] = 1;
					} else if (i == 0 && j > 0) {
						a[0][j] = a[0][j - 1];
					} else if (j == 0 && i > 0) {
						a[i][0] = a[i-1][0];
					} else {
						a[i][j] = a[i-1][j] + a[i][j-1]
					}
				}
			}
		}
		System.out.println(a[x][y]);

	}
}


C语言的也差不多,就不写了,这也是看了其他大佬的。
注意一点是 这个走格子和走点是一样的,

在这里插入图片描述
以输入样例 6×6,马在 (3,3) 为例,左至右分别为 x,上至下分别为 y。

下面顺便对样例进行一下解释:
其中 PP 点为马的控制点。我们不妨把马的控制点 g[x][y]g[x][y] 标记为 1。

样例共有 6 条路径

大家仔细观察一下,马在第一排 (y=0)(y=0) 的走法有三种:

第一排走到底,再走到目标点;
第一排走到第四个 0 的位置,这里大家可以看出有一种路径;
第一排走到倒数第二个 0 的位置,拐个弯到达目标位置;
这里总共 3 种走法; 在第一列 (x=0)(x=0) 的走法有两种,分别是:

第一列走到倒数第二个 0 的位置,拐个弯到达目标位置;
第一列走到第四个 0 的位置,大家可以看出有一种路径;
第一列走到底,再走到目标点;
这里总共有 3 种走法;加上前面的3种,共有6种!

看到这里,大家应该明白了题意,现在我们看输入输出:

输入前两个数,为棋盘的长宽;
输入后两个数,为马的坐标 ( x , y ) (x,y) x,y)

这里告诉大家一个公式(证明度娘)

在平面内,从点 (0,0)(0,0) 到点 (x,y)(x,y) 的路径数f[x][y]=f[x-1][y]+f[x][y-1]f[x][y]=f[x−1][y]+f[x][y−1]
现在解释一下:其实就是一个简单的 DPDP 方程(或者说递推式),到达一个点 (x,y)(x,y),可能从 (x-1,y)(x−1,y) 或者 (x,y-1)(x,y−1) 走来,因此方案数为到 (x-1,y)(x−1,y) 和到 (x,y-1)(x,y−1) 方案的总和。

然后就可以愉快的开始搜索了,思路有两种:

dfs 深搜+回溯(即递归搜索)
递推(或者说是 DPDP)
不论是递推或是递归,都要确定边界:

根据上述公式,数组不能越界对吧?

递推:

若 x=0x=0,则 f[x][y]=f[0][y-1]f[x][y]=f[0][y−1](自己画图思考一下)
若 y=0y=0,则 f[x][y]=f[x-1][0]f[x][y]=f[x−1][0]
当 g[x][y]=1g[x][y]=1 的时候,肯定不能搜索啦(f[x][y]=0f[x][y]=0 )
最后,写个 else (上述公式) 就好了

上面的方法是对于如果只是从某一个点到另一个点的路径数的总和,没有什么不能经过的点。

这里还要提个醒:这题不需要高精,long 就可以了!(讲解部分为大佬的,确实很好了)

以下是C语言洛谷p1002过河卒的代码实现和注释解析: ```c #include <stdio.h> #define MAX 21 // 定义最大值 int main() { int n, m, xh, yh, i, j, k; long long map[MAX][MAX] = {0}; // 定义地图,初始化为0 scanf("%d %d %d %d", &n, &m, &xh, &yh); // 输入信息 map[xh][yh] = -1; // 标记障碍物 for (k = 0; k < 3; k++) { // 遍历3个方向 switch (k) { case 0: i = 2; j = 1; break; // 方向1 case 1: i = 1; j = 2; break; // 方向2 case 2: i = 1; j = 1; break; // 方向3 } if (xh - i >= 0 && yh - j >= 0) { // 判断是否越界 map[xh - i][yh - j] = -1; // 标记障碍物 } if (xh + i <= n && yh + j <= m) { // 判断是否越界 map[xh + i][yh + j] = -1; // 标记障碍物 } } map[0][0] = 1; // 起点为1 for (i = 0; i <= n; i++) { // 遍历行 for (j = 0; j <= m; j++) { // 遍历列 if (map[i][j] != -1) { // 判断是否为障碍物 if (map[i - 1][j] != -1) { // 上可通过 map[i][j] += map[i - 1][j]; // 累加上方格子的值 } if (map[i][j - 1] != -1) { // 左可通过 map[i][j] += map[i][j - 1]; // 累加左方格子的值 } } } } printf("%lld\n", map[n][m]); // 输出结果 return 0; } ``` 注释解析: 1. 定义了一个二维数组`map`,用于存储地图信息,初始化为0。 2. 输入了4个整数,分别为地图的行数`n`、列数`m`、的初始位置`xh`、`yh`。 3. 标记了障碍物,即不能到达的位置。 4. 遍历了3个方向,分别为向上2步、向左1步;向上1步、向左2步;向上1步、向左1步。如果可以到达该位置,则标记为障碍物。 5. 起点的值为1,表示只有一种法。 6. 遍历整个地图,如果该位置不是障碍物,则累加上方格子和左方格子的值。 7. 输出结果,即终点的值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值