1.简介
象棋是作为中华民族的瑰宝,其中映射了很多数学问题。卒在过河后可以前进、右移动。马则可以走日字。现在有一道题目。棋盘上 A (0,0)点有一个过河卒,需要走到目标B(n,m) 点。同时在棋盘上 C(x,y)点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点89。因此称之为“马拦过河卒”。范围如下n>=1,m<=20,x>=1||x<=20,y>=1||y<=20。
2.分析
(1)首先我们需要分析出不能落子的点及控制点。控制点与马的距离是根号五,所以在后期回溯时候我们用当前坐标与马之间的距离作比较如果等于根号五则舍弃。
(2)在计算方案时候我们运用一个最基本的数学思维,所有路径的情况和就是总路径
如下图进行分析。最后到达B点的最短路径情况就是相邻两点的和。所以每次我们只要累加两个角上的路径值就可以了。
3.代码实现
3.1变量的声明
(1)声明一个二维数组num[ i ] [ j ]来表示他的路线条数
(2)声明两个变量x,y来表示终点坐标
(3)声明两个变量a,b来表示马的位置
(4)声明两个变相i,j来表示实际坐标
3.2判断马眼睛的位置
根据我们的分析可以根据距离来确定是否为马眼。
if (((a-i)*(a-i)+(b-j)*(b-j)==5)||(i==a&&j==b))//判断卒是否走到了马眼
3.3进行遍历
(1)我们首先考虑特殊情况就是边界的行和列,他们只有一种走法所以我们先对其进行求解,代码如下
for ( i= 0; i < x; i++) { num[i][0]=1; } for ( j = 0; j < y; j++) { num[0][j]=0; }
(2)然后就到了我们的核心算法,对中心区域进行求解。由分析可知,卒只有两个方向可以走。则推出该公式。
num[i][j]=num[i-1][j]+num[i][j-1]; //此时i,j均位于边缘所以采用减法 for ( i = 1; i <= x; i++) { for ( j = 1; j <= y; j++) { if (((i-a)*(i-a)+(j-b)*(j-b)==5)||(i==a&&j==b))//判断卒是否走到了马眼 num[i][j]=0; else num[i][j]=num[i-1][j]+num[i][j-1]; } }
4.完整代码
#include<stdio.h> int main(int argc, char const *argv[]) { int x,y,a,b,i,j;//x,y表示终点坐标,a,b表示马的坐标,i,j表示行走的坐标(i是行,j是列) int num[i][j];//数组num表示路径数 scanf("%d%d",&x,&y); scanf("%d%d",&a,&b); for ( i= 0; i <= x; i++) { num[i][0]=1; } for ( j = 0; j <= y; j++) { num[0][j]=1; } for ( i = 1; i <= x; i++) { for ( j = 1; j <= y; j++) { if (((i-a)*(i-a)+(j-b)*(j-b)==5)||(i==a&&j==b))//判断卒是否走到了马眼 num[i][j]=0; else num[i][j]=num[i-1][j]+num[i][j-1]; } } printf("%d",num[x][y]);//num数组中存储了所有的路径,我们只是取出看其中x,y我们所需要的坐标的路径数。 return 0; }
5.总结
1.注意本方法实际上求出了到达每一个点的方案个数,然后通过选择我们需要的坐标(x,y)来取出我们所需要的路径解。
2.判断马是否在马眼上的,如果在马眼上则经过该点所有方案记为0.
3.本方法是按行进行计算的。