【递推与递归】【JAVA】P1002 [NOIP2002 普及组] 过河卒

在这里插入图片描述

思路:对于这道题,之前在写欧拉计划系列的时候曾经遇到过,当时用动态规划可以直接求出结果,这道题相当于是在基础上加了一个障碍点,在寻找路径的过程中需要跳过这些的障碍点,基本思路有了,接下来就认真分析一下怎么去实现这个算法。

分析:

1.状态转移方程

在二维坐标系中寻找从A点到B点的所有路径,而且只允许往右和往下,每次只能走一步,A点到自身的路径只有一条,这里假设B坐标为(i,j),那么上一步到达B的方式只有两种(i-1,j)和(i,j-1),从A到达B的所有路径和是在上一次走的路径基础上求和,那么就可以得出状态转移方程f(i,j)=f(i-1,j)+f(i,j-1)

2.跳过障碍点

玩过象棋的人应该知道,马走日(不知道也不要紧,题上给出了演示),那么我们根据输入的马的坐标可以得到马所控制的位置(马自身的位置也是被控制的,马一共控制九个位置),通过对马所控制位置做上标记,当用状态转移方程求路径和的时候跳过这些点就可以了。

3.需要注意

做完分析就该写代码了,这里有几个坑要避一下,数组越界,数组起始值为0,我们的起点应该定为1(防止状态转移方程数组越界),而又因为要对马能到达的位置做上标记,那么起点应该从2开始(防止对马能到达位置进行标记时越界),;开两个数组,对于java,定义一个数组的默认值是0,而我们对马到达的地方进行标记就不能用0了,而用其他数又会对结果造成影响(比如标记为-1,我们跳过障碍点了,但是障碍点附近的点求路径和的时候会把障碍点的值记录进去,对结果造成影响),所以这里一个数组作为标记数组,一个作为结果数组,最后输出结果数组就行。

package LOQ.递推与递归;

import java.util.Scanner;

/**
 * 动态规划
 * 起始位置只有一种路径,下一次走的位置的方法是由上一次所组成的,最终问题的解是由前面的解所构成
 * 1.输入:B坐标和马的坐标
 * 2.输出:从A到B的总路径数
 * 算法
 * //对马能到达的位置做上标记,包括马自身的位置
 * dp[i][j]=-1
 * res[2][2]=-1
 * for i ← 2 to n do
 *  for j ← 2 to m do
 *      res[i][j]=res[i-1][j]+res[i][j-1];
 */
public class P1002过河卒 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        //防止出现越界,将坐标都向右下角平移一个单位
        int n = sc.nextInt() + 2, m = sc.nextInt() + 2, b1 = sc.nextInt() + 2, b2 = sc.nextInt() + 2;
        //定义二维坐标系 n+1为了包括n
        int[][] dp = new int[n + 1][m + 1];
        long[][] res = new long[n + 1][n + 1];
        //将马能到达的位置做上标记,包括马的位置
        dp[b1][b2] = -1;
        dp[b1 + 2][b2 + 1] = -1;
        dp[b1 + 1][b2 + 2] = -1;
        dp[b1 - 1][b2 - 2] = -1;
        dp[b1 - 2][b2 - 1] = -1;
        dp[b1 - 1][b2 + 2] = -1;
        dp[b1 - 2][b2 + 1] = -1;
        dp[b1 + 2][b2 - 1] = -1;
        dp[b1 + 1][b2 - 2] = -1;
        dp[2][2] = -1;
        //起点值为2
        res[2][2] = 1;
        for (int i = 2; i <= n; i++) {
            for (int j = 2; j <= m; j++) {
                //马可以到达 将结果集赋值
                if (dp[i][j] == 0) {
                    res[i][j] = res[i - 1][j] + res[i][j - 1];
                }
            }
        }
        System.out.println(res[n][m]);
    }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值