P1002 [NOIP2002 普及组] 过河卒

本文介绍了一道经典的动态规划问题——过河卒问题。卒从起点到终点,需避开对方马的控制范围。文章详细解析了动态规划方程的设计过程,并提供了完整的代码实现。

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

P1002 [NOIP2002 普及组] 过河卒

最近在洛谷刷题,决定用博客把自己的解题思路以及踩过的坑整理总结一下~

先来看看题目吧~

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

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

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

输入格式
一行四个正整数,分别表示 BB 点坐标和马的坐标。

输出格式
一个整数,表示所有的路径条数。

思路

刚拿到题的时候,有点不知道怎么做,只觉得要用动态规划,但是没有想好方程是怎么样的。
错得离谱的思路就不说了,说说还不错的思路。
定义一个数组用来存到该点的路径条数路径条数怎么得到呢?
往下看
因为只能向下或向右去走,所以到一个点只有通过它左边的路或上边的路
那么来了!!!
到某点的路径条数=到它左边点的条数+到它上面点的条数(前提是这两点都可到)
这时候我们想一想就可以得到动态规划方程
不过我这里倒是犯了一个错误,我想当然的把到边线上的点的路径条数默认成1了,虽然一般情况适用,可是当马的控制范围包含了某个边线上的点时,是WA了!
真正到边线上的点的路径条数应该是他的上一个点的条数(上边界就是它左边的点,左边姐就是它上边的点)

               if(i==0&&j>0)//上边界
                {
                    a[i][j]=a[i][j-1];

                }
                else if(j==0&&i>0)//左边界
                {
                    a[i][j]=a[i-1][j];
                }

那么还有一个特殊点,就是原点(起点),到它的路径条数是多少呢?
很明显,就是1

				if(i==0&&j==0)//原点
                    a[i][j]=1;

剩下的点就是普通点了,到它们的路径条数当然就是到它左边点的条数+到它上面点的条数

				else
                {
                        a[i][j]=a[i-1][j]+a[i][j-1];
                }

要注意!!我们讨论的这三类点都是在它可到达的情况下讨论的,也就是说不受马控制的点,那么怎么实现呢?
当然在外面加一层if判断就好了!
好了,到这里,方程就基本出来了,剩下的就看代码吧,呼呼~

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n,m,p,q;//(n,m)终点  (p,q)马点
	long long a[30][30];//路径条数,之前这里用了int,总有两个测试数据不过
						//改成longlong就好了
    int map[30][30];//能不能走,马控制的点设为1,代表不能走

    cin>>n>>m>>p>>q;
    
    //马的控制区域,1代表此路不通
    map[p][q]=1;
    map[p-2][q-1]=1;
    map[p-2][q+1]=1;
    map[p+2][q+1]=1;
    map[p+2][q-1]=1;
    map[p-1][q-2]=1;
    map[p-1][q+2]=1;
    map[p+1][q+2]=1;
    map[p+1][q-2]=1;


    /* 嘤嘤嘤 这里就是错误代码了,异想天开的我,以为边线上的点一定可以到。。。
    for(int i=1;i<=n;i++)
    {
        a[i][0]=1;
    }
    for(int i=1;i<=m;i++)
    {
        a[0][i]=1;
    }*/
    
    //动态规划求到各点的路数
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<=m;j++)
        {
            if(map[i][j])
                continue;
            else //不受马控制的点
            {
                if(i==0&&j==0)
                    a[i][j]=1;
                else if(i==0&&j>0)
                {
                    a[i][j]=a[i][j-1];

                }
                else if(j==0&&i>0)
                {
                    a[i][j]=a[i-1][j];
                }
                else
                {
                        a[i][j]=a[i-1][j]+a[i][j-1];
                }
            }
        }
    }
    cout<<a[n][m]<<endl;
    return 0;
}

over,这道题就结束了~~第一次写博客,如果有帮到大家,非常荣幸,写得不好,也请见谅,啦啦

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值