「过河卒」题目

洛谷题目<过河卒>

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

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

在这里插入图片描述

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

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

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

输入输出样例
输入
6 6 3 3
输出
6
说明/提示
对于 100 % 的数据,1<=n,m<=20,0<=马的坐标<=20.

分析一下
第一种想法,这道题刚入手的时候,想到的是通过查找,由于数据较小,可以将所有的点通过二维数组表示出来,能够通过的点就赋值为1,不能通过的点就赋值为0。但是仔细想过后,发现不能够解决问题,当面临着可以向下走,也可以向左走的时候,该如何选择?就算选择了其中一种路径,可是继续走下去后,假如到达目标点或者遇到了死胡同,不能继续往前走了,又该如何返回并尝试另一种路径呢?
以上问题让我当时否定了我的这种想法,也许以后能够有办法解决,但是目前这个问题我一点思路还都没有。
第二种想法,我想到由一个点在坐标轴中到达另一个点的路径有多少种的问题,我在高中曾经遇到过这种数学题,也就是排列组合C(n,m),这个想法给我提供了另一种思路,假如说从点(0,0)到达点(3,4)的话,路径一共有C(7,3)或C(7,4)种。也许能够通过这个办法解决这个问题。可以先计算出由点(0,0)到(n,m)的总路径数,然后减去那些经过了马的控制点的路径,这个计算可以通过由点(0,0)到马的控制点的路径数 乘以 该控制点到目标点的路径数,但是减去的过程中,还会减去经过两个马的控制点的路径数(那些重复的部分)。这样下来,计算量会非常的大,而且很容易就多减去了,这种方法可能在最后我抽丝剥茧后会得出来正确结果,但是这种复杂程度,太容易错误。

重点来啦
最后我在洛谷上看了大神的题解,了解到一种方法:假设到达点(i,j)的路径数为f[i][j]条,那么f[i][j]=f[i-1][j]+f[i][j-1]。这个是重点,那么就可以通过递推来计算出到达那个点的路径。
上代码

#include<iostream>
using namespace std;
//20-7-8改 下面被注释掉的部分是昨天7-7写的,可惜写了半天,还是没写出来,于是今天去落谷上看题解了,有了一些思路,再来。
int main()
{
	int n,m,x,y,i,j;
	long long f[25][25]={0};
	int g[25][25]={0};
	cin>>n>>m>>x>>y;
	//防止越界 
	if(x<=18 && y<=19)
		g[x+2][y+1]=1;
	if(x<=19 && y<=18)
		g[x+1][y+2]=1;
	if(x>=1 && y<=18)
		g[x-1][y+2]=1;
	if(x>=2 && y<=19)
		g[x-2][y+1]=1;
	if(x>=2 && y>=1)
		g[x-2][y-1]=1;
	if(x>=1 && y>=2)
		g[x-1][y-2]=1;
	if(x<=19 && y>=2)
		g[x+1][y-2]=1;
	if(x<=18 && y>=1)
		g[x+2][y-1]=1;
	g[x][y]=1 ;
	//递推实现
	for(i=0;i<=n;i++)
		for(j=0;j<=m;j++)
			if(!g[i][j])//不为马的控制点时 
			{
				if(i==0 && j==0)
					f[0][0]=1;//最初
				else if(i==0 && j>0)
					f[0][j]=f[0][j-1];
				else if(i>0 && j==0)
					f[i][0]=f[i-1][0];
				else 
					f[i][j]=f[i-1][j]+f[i][j-1];	
			 } 
		cout<<f[n][m]<<endl;
		return 0;
 } 
 //下面这部分是我第二种思路,可惜最后失败了。
//#include <iostream>
//using namespace std;
//int cou(int x,int y)
//{
//	if(x<0 || y<0)
//	{
//		return(0);
//	}
//	int i,j,sum1=1,sum2=1,n,sum;
//	n=x+y;
//	for(i=n,j=1;j<=x;i--,j++)
//	{
//		sum1=i*sum1;
//	}
//	for(i=1;i<=x;i++)
//	{
//		sum2=i*sum2;
//	}
//	sum=sum1/sum2;
//	return sum;
//}
//int main()
//{
//	int a[28];
//	int i,j,m,n,x,y,sum;
//	cin>>n>>m>>x>>y;
//	sum=cou(n,m);
//	a[0]=cou(x+2,y+1)*cou(n-x-2,m-y-1);
//	a[1]=cou(x+1,y+2)*cou(n-x-1,m-y-2);
//	a[2]=cou(x-1,y+2)*cou(n-x+1,m-y-2);
//	a[3]=cou(x-2,y+1)*cou(n-x+2,m-y-1);
//	a[4]=cou(x-2,y-1)*cou(n-x+2,m-y+1);
//	a[5]=cou(x-1,y-2)*cou(n-x+1,m-y+2);
//	a[6]=cou(x+1,y-2)*cou(n-x-1,m-y+2);
//	a[7]=cou(x+2,y-1)*cou(n-x-2,m-y+1);
//	for(i=0;i<8;i++)
//	{
//		sum=sum-a[i];
//	}
//	a[0]=cou(x-1,y+2)*cou(n-x-1,m-y-2);
//	a[1]=cou(x-2,y+1)*2*cou(n-x+1,m-y-2);
//	a[2]=cou(x-2,y-1)*cou(1,3)*cou(n-x+1,m-y-2);
//	a[3]=cou(x-1,y-2)*cou(n-x+1,m-y-2);
//	a[4]=cou(x-2,y+1)*cou(3,1)*cou(n-x-1,m-y-2);
//	a[5]=cou(x-2,y-1)*cou(3,3)*cou(n-x-1,m-y-2);
//	a[6]=cou(x-1,y-2)*cou(2,4)*cou(n-x-1,m-y-2);
//	a[7]=cou(x+1,y-2)*cou(n-x-1,m-y-2);
//	a[8]=cou(x-2,y+1)*cou(n-x-2,m-y-1);
//	a[9]=cou(x-2,y-1)*cou(4,2)*cou(n-x-2,m-y-1);
//	a[10]=cou(x-1,y-2)*cou(3,3)*cou(n-x-2,m-y-1);
//	a[11]=cou(x+1,y-2)*cou(1,3)*cou(n-x-2,m-y-1);
//	a[12]=cou(x+2,y-1)*cou(n-x-2,m-y-1);
//	a[13]=cou(x-2,y-1)*cou(n-x+2,m-y-1);
//	a[14]=cou(x-2,y-1)*cou(n-x-2,m-y+1);
//	a[15]=cou(x-1,y-2)*cou(n-x-1,m-y+2);
//	a[16]=cou(x+1,y-2)*cou(n-x-2,m-y+1);
//	a[17]=cou(x-2,y+1)*2*cou(n-x-1,m-y-2);
//	a[18]=cou(x-2,y-1)*cou(1,2)*cou(n-x-1,m-y-2);
//	a[19]=cou(x-1,y-2)*cou(n-x-1,m-y-2);
//	a[20]=cou(x-2,y-1)*2*cou(n-x+1,m-y-2);
//	a[21]=cou(x-1,y-2)*cou(n-x-1,m-y-2);
//	a[22]=cou(x-2,y-1)*cou(n-x-2,m-y-1);
//	a[23]=cou(x-1,y-2)*cou(n-x-2,m-y-1);
//	a[24]=cou(x-1,y-2)*cou(3,1)*cou(n-x-2,m-y-1);
//	a[25]=cou(x+1,y-2)*2*cou(n-x-2,m-y-1);
//	a[26]=cou(x-2,y-1)*cou(n-x-2,m-y-1);
//	a[27]=cou(x-1,y-2)*2*cou(n-x-2,m-y+1);
//	for(i=0;i<28;i++)
//	{
//		sum=sum+a[1];
//	}
//	cout<<sum<<endl;
//}

第一次写,: ) 有点乱,以后尽量改一下。

再来个大神题解链接吧

添加链接描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值