解题思路
这道题用动态规划,由题意只马只能向上走,因此马要一步到某一位置最多有如下图所示四种线路。
下图以4行4列的棋盘为例,格子中的数字代表马到这个位置的走法,可由上述方法得到,即从下往上、从左往右依次遍历到各位置的路径数,最后即可得出结果。
再优化
从上图不难发现,有不少格子是不可能到达的,那么如果可以找到这些不可到达的格子的位置规律,就可以少遍历很多格子,从而提高效率了。仔细看下图(以5行6列为例),我们会发现一个规律:
线段1连接的几个圆圈代表马在对应行能到达的最右位置,线段2连接的几个圆圈代表马要到达终点在对应行的最左位置,因此线段1的右侧区域是马不能到达的,线段2的左侧区域是马无法到达终点的,所以仅需遍历下图所示区域:
如果我们再仔细观察,会发现还可以再简化,线段1左侧2格与线段2右侧1格也同样无需遍历,原因是前者到达不了,而后者无法达到终点,此时我们需要遍历的就只有下图几个位置了:
代码
#include <iostream>
#define Mod 1000000007;
using namespace std;
long long map[105][105] = {0};
int main()
{
int n, m;
cin >> n;
cin >> m;
if (m == 2 * n - 1)
{
cout << 1 << endl;
}
else if (m >= 2 * n || m == 2 * n - 2 || m == 2 * n - 3 || m == 1)
{
cout << 0 << endl;
}
else if (n == 2)
{
if (m == 3)
{
cout << 1 << endl;
}
else
{
cout << 0 << endl;
}
}
else
{
map[1][1] = 1;
map[2][3] = 1;
for (int i = 3; i <= n; i++)
{
int begin = m - 2 * (n - i);
for (int j = begin > 0 ? begin : 1; j <= 2 * i - 1 && j <= m; j++)
{
if (j == begin + 1 || j == begin + 2 || j == 2 * i - 2 || j == 2 * i - 3)
{
continue;
}
map[i][j] = (map[i][j] + map[i - 2][j - 1]) % Mod;
map[i][j] = (map[i][j] + map[i - 2][j + 1]) % Mod;
map[i][j] = (map[i][j] + map[i - 1][j + 2]) % Mod;
if (j > 1)
{
map[i][j] = (map[i][j] + map[i - 1][j - 2]) % Mod;
}
}
}
cout << map[n][m] << endl;
}
return 0;
}