洛谷 P1002 过河卒

原题链接

收回我的话,前面有些题的难度还是非常大的。
第一次接触动态规划。
参加过高考的同学应该会记得一个数学题,就是
在这里插入图片描述
对于一个有nxm个点构成的矩阵,从左上走到右下,有多少种走法,每次只能向右或者向下走。
答案是 从m+n里选择m 的组合数。
原因也很简单,最后走过的轨迹一定是一条忽右忽下的折线,总长由平移知为m+n,从中取m步向右,或者取n步向右即可。对于红点,最后一步总是从蓝点走的,到红点的步数=到蓝点1的步数+到蓝点2的步数。
在这道数学题中,这样就很容易验证C(m+n,m)=C(m+n-1,n)+C(m+n-1,m)。
所以我们计算(m,n)点的步数时,就把问题退化了,这就是动态规划的思想。
把这种思想运用在本题中即可。
我们把被马约束的地方的步数记为-1,从起点到起点的走法数位1,按照以上的推导,我们就能逐渐写出到所有点的走法数(写有-1的地方不再考虑,也对相邻格子的步数没有贡献。)
由数学题来推这个,其结果也是按阶乘规律变大的,所以棋盘保存的步数可能很大,要用long long数组。

#include <stdio.h>
typedef long long ll;//参考别人代码的时候发现的,这样long long写起来会方便很多 
int main(int argc, char const *argv[])
{
	ll sheet[21][21]={0},i,j;//sheet表示整个棋盘,棋盘上(x,y)点的值,也就是sheet[x][y],表示从原点到该点的走法数 
	int blocked[9][2] = { {1,2},{-1,2},{1,-2},{-1,-2},
                     {2,1},{-2,1},{2,-1},{-2,-1},
					 {0,0}}; //blocked数组记录了所有管辖的位置相对于马原来坐标的x,y偏移,需要注意的是还有马原来的位置也是被约束的 
    int x,y;//临时坐标(x,y) 
	int b_x,b_y,ma_x,ma_y;scanf("%d%d%d%d",&b_x,&b_y,&ma_x,&ma_y);//(b_x,b_y)是目标点B坐标,(ma_x,ma_y)是马所在点坐标 
	for(i=0;i<9;i++)
		{
			x=blocked[i][0]+ma_x;
			y=blocked[i][1]+ma_y;
			//马的坐标加上每组的x,y偏移量,得到被管辖的点 
			if((0<=x&&x<=b_x)&&(0<=y&&y<=b_y))//如果这个点在 原点 和 B点之间,就将其棋盘上的值设为-1,表示不可能通过此处 
				sheet[x][y]=-1;
		}		
	sheet[0][0]=1;//重要:记得赋初值,不然怎么搞都是0,从原点到原点当然只有一种走法 
	for(i=0;i<=b_x;i++)
		for(j=0;j<=b_y;j++)
		//填充棋盘 
		{
			if(sheet[i][j]==-1) continue;//遇到被约束的点直接跳过 
			//到点(i,,j) 的走法数 = 到点(i-1,j)的走法数 + 到点(i,j-1)的走法数
			//要保证后面两个点在范围内,由于是减法,只需要考虑下界 
			if(i-1>=0&&sheet[i-1][j]!=-1)
				sheet[i][j]+=sheet[i-1][j];
			if(j-1>=0&&sheet[i][j-1]!=-1)
				sheet[i][j]+=sheet[i][j-1];
		}
	printf("%lld",sheet[b_x][b_y]);
	return 0;
}

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

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

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

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

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

输入输出样例
输入样例#1: 复制
6 6 3 3
输出样例#1: 复制
6
说明
结果可能很大!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值