实现思路:
过河卒问题实际是一种递推问题,也用到了动态规划的思想。
首先要能够标记出马的位置以及马的控制点所在的位置,这也就用到了方向数组bx[8]和by[8],用作移动时不同方向的移动。以x轴为横坐标,y轴为纵坐标,可以得出p1的坐标为马的横坐标+2,马的纵坐标+1;p2的坐标为马的横坐标+1,马的纵坐标+2;p3的坐标为马的横坐标-1,马的纵坐标+2.......以此类推,即可得出全部马的控制点相对于马的坐标的位置偏移量,将这些偏移量的横坐标计入数组bx[8]中,纵坐标计入数组by[8]中,可以得出马和马的控制点在二维数组中的所有坐标。
接下来要用到标记数组vis,将马和马的控制点所在的坐标记为1,其余的保持默认值0不变即可。这里注意,能够置为1的马的控制点一定要保持在整个二维数组的范围中,不能越界。
为了获取在二维数组中到达每一个点的路径数目,则需要数组边界点的路径数目作为基础来进行递推,同时需要推断出其动态转移方程。如下图所示递推规律。
如图所示,在每个点的地方所标的数字就是从原点开始能够到达该点的路线的条数,根据上图可以得出状态方程为f[ i ][ j ] =f[ i-1][ j ]+f[ i ][ j-1 ],这样可以算出没有障碍物时,到达某点的路径条数。
接下来考虑有障碍物时(即马和马的控制点),路径条数所发生的变化。
首先是边界点,如果在边界处存在马和马的控制点,那么从这点开始,这条边界往后的点都不会再有路径通过,相当于遇到了“死路”。
如果在中间的点处有马和马的控制点,则在进行递推时这部分路径也就不能算了,将其置为0.
最后输出要求点的路径条数即可。
代码如下;
#include <iostream>
#include <string>
#include <queue>
using namespace std;
int bx[8] = { 2,-2,2,-2,1,1,-1,-1 };//马的控制点的横坐标数组
int by[8] = { 1,-1,-1,1,2,-2,2,-2 };//马的控制点的纵坐标数组
bool vis[101][101] = {0};
int f[101][101] = { 0 };//每个点的路径数
int main()
{
int n = 0, m = 0;//n,m是结束点的坐标
cin >> n >> m;
int x=0, y = 0;//mx,my是马的坐标
cin >> x >> y;
vis[x][y] = 1;//将马标记
for (int i = 0; i < 8; i++)
{
int cx = x+bx[i];
int cy = y+by[i];
if (cx >= 0 && cx <= n && cy >= 0 && cy <= m)//防止马的控制点越界
{
vis[cx][cy] = 1;//标记马的控制点
}
}
f[0][0] = 1;//第一个点只有一条路径
if (vis[0][0] == 1) f[0][0] = 0;//如果第一个点就是马或马的控制点,则直接被锁死
for (int j = 1; j <= m; j++)//处理列边界
{
f[0][j] = f[0][j - 1];
if (vis[0][j] == 1) f[0][j] = 0;
}
for (int i = 1; i <= n; i++)//处理行边界
{
f[i][0] = f[i - 1][0];
if (vis[i][0] == 1) f[i][0] = 0;
}
for (int i = 1; i <=n; i++)
{
for (int j = 1; j <= m; j++)
{
f[i][j] = f[i - 1][j] + f[i][j - 1];
if (vis[i][j] == 1) f[i][j] = 0;//在递推过程中间位置遇到马的控制点
}
}
cout << f[n][m]<<endl;
return 0;
}