过河卒
过河卒
本题链接:p1002 过河卒
题目描述
棋盘上 $ A $ 点有一个过河卒,需要走到目标$ B $点。卒行走的规则:可以向下、或者向右。同时在棋盘上 $ C $ 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,$ A $ 点 $ (0,0) $ 、$ B $ 点 $ (n,m) $ ,同样马的位置坐标是需要给出的。
现在要求你计算出卒从 $ A $ 点能够到达 $ B $ 点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
输入格式
一行四个正整数,分别表示 $ B $ 点坐标和马的坐标。
输出格式
一个整数,表示所有的路径条数。
说明/提示
对于100%的数据, $ 1≤n,m≤20 $ ,$ 0≤ $ 马的坐标 $ ≤20 $。
求解
我看到这题时,我就想到用递推来做这题
1. 根据题意并根据样例,第一步可以写出下列 (简单的) 表格:
[0] | [1] | [2] | [3] | [4] | [5] | [6] | |
---|---|---|---|---|---|---|---|
[0] | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
[1] | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
[2] | 1 | 3 | 6 | 10 | 15 | 21 | 28 |
[3] | 1 | 4 | 10 | 20 | 35 | 56 | 84 |
[4] | 1 | 5 | 15 | 35 | 70 | 135 | 219 |
[5] | 1 | 6 | 21 | 56 | 126 | 261 | 370 |
[6] | 1 | 7 | 28 | 84 | 210 | 471 | 841 |
(显而易见),这里可以利用加法原理,写出递推式:
\[f[i][j]=f[i-1][j]+f[i][j-1];(start:f[0][0]=1)
\]
2. 第二步再加上马的影响
[0] | [1] | [2] | [3] | [4] | [5] | [6] | |
---|---|---|---|---|---|---|---|
[0] | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
[1] | 1 | 2 | 0 | 1 | 0 | 1 | 2 |
[2] | 1 | 0 | 0 | 1 | 1 | 0 | 2 |
[3] | 1 | 1 | 1 | 0 | 1 | 1 | 3 |
[4] | 1 | 0 | 1 | 1 | 2 | 0 | 3 |
[5] | 1 | 1 | 0 | 1 | 0 | 0 | 3 |
[6] | 1 | 2 | 2 | 3 | 3 | 3 | 6 |
根据这个表格,我们可以想到先把马的控制点,也就是马能到达的地方(包括他本身的这个点,做一个预处理,之后递推的时候,如果到达马的控制点,直接跳过,继续下一个点。
基本思路就是这样,但是在测评中发现了第三个点:只有long long类型才能AC。
代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
int n,m,x,y;
long long map[42][42]={{1}}; \\递推开始式为f[0][0] = 1;
bool horse[42][42];
int hx[9]={0,1,1,2,2,-1,-1,-2,-2}, \\马的位移
hy[9]={0,2,-2,1,-1,2,-2,1,-1};
int main ()
{
cin>>n>>m>>x>>y;
for (int i=0;i<=8;i++)
{
int xx=x+hx[i],yy=y+hy[i];
if (xx>n||xx<0||yy>m||yy<0)
continue;
horse[xx][yy]=1;
}
int l=0,k=0;
while (!horse[0][++k]&&k<=m)
map[0][k]=1;
while (!horse[++l][0]&&l<=n)
map[l][0]=1;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (!horse[i][j])
map[i][j]=map[i-1][j]+map[i][j-1]; \\递推式
cout<<map[n][m]<<endl;
return 0;
}