(动态规划)洛谷1002 过河卒

目录

题目概述:

AC代码:

分析思路:


 

题目概述:

 

AC代码:

 

#include<iostream>
#include<cstring>
using namespace std;
#define ll long long
#define maxsize 20
ll dp[maxsize+1][maxsize+1];
int d[9][2]={{0,0},{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1}};
int main()
{
	std::ios::sync_with_stdio(false);
	int fx,fy,hx,hy;
	cin>>fx>>fy>>hx>>hy;
	dp[0][0]=1;
	dp[0][1]=1,dp[1][0]=1;
	for(int i=0;i<9;++i)
	{
		int nx=hx+d[i][0],ny=hy+d[i][1];
		if(nx<0||ny<0||nx>fx||ny>fy)
		continue;
		dp[nx][ny]=-1;//-1标记控制点 
	}
	for(int i=0;i<=fx;++i)
	for(int j=0;j<=fy;++j)
	{
		if(dp[i][j]==-1)//如果已经是控制点 
		{
			dp[i][j]=0;
			continue;
		}
		if(dp[i][j]==1)
		continue;
		if(i)
		dp[i][j]+=dp[i-1][j];
		if(j)
		dp[i][j]+=dp[i][j-1];
	}
	cout<<dp[fx][fy]<<endl;
	return 0;
}

分析思路:

1.首先,我们定义dp[i][j]为到达坐标(i,j)的方法 那么除去边界的一些特殊情况 卒可以向右或者向下 那么dp[i][j]=dp[i-1][j]+dp[i][j],也就是前一步向右到达的方法数加上前一步向下到达的方法数。

2.接下来考虑一些特殊情况。首先应该知道对于一个方形棋盘,左边界上坐标到达只能通过向下到达,上边界上坐标只能通过向右到达,也就是对于j=0和i=0的情况。需要在循环中特殊处理。

3.接下来还剩下两件事情,一个是马的封锁,一个是递推初始条件。应该先处理哪个?应该是递推初始条件。如果顺序颠倒 第四个测试点(19,19,1,0)就会WA。为什么呢?在这里,我们用d[9][2]作为马封锁点的偏移量,把dp中对应位置改为-1,进入循环时检查,如果是-1就改成0直接退出,因为封锁过的点至始至终到达他的办法数量都只能是0。

4.那么递推初始条件呢?表面上好像很容易,dp[0][0]=1,dp[0][1]=1,dp[1][0]=1。但是问题就出在这里。有可能第一步向右或者向下路径就已经被封锁如(19,19,1,0),从(0,0)出发只能向右走,dp[0][1]=0而不是1。所以要先初始化递推初始条件,再进行马的封锁,这样马的封锁能够覆盖前面初始条件。

5.最后一个坑点是,这题dp数组要使用long long类型,当靠近数据范围边界时,int类型会爆。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

102101141高孙炜

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值