题目描述

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

棋盘用坐标表示,\(A\)\((0, 0)\)\(B\)\((n, m)\)(\(n\), \(m\)为不超过\(20\)的整数),同样马的位置坐标是需要给出的。

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

输入输出格式

输入格式:

一行四个数据,分别表示\(B\)点坐标和马的坐标。

输出格式:

一个数据,表示所有的路径条数。

输入输出样例

输入样例#1:

6 6 3 3 ## 输出样例#1: 6 # 说明 结果可能很大! * * *

看到题目二话不说用了搜索,直到在提交前看了一下算法标签,又看了一下数据范围。。。

状态转移方程的推导并不复杂,每次判断卒是否能走到这个格子,不可以则为0(显而易见),可以则为下方与左方的值之和。

上代码,这道题算是一道DP入门题吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include<stdio.h>

const int MAXN = 20 + 5;
const int attack[9][2] = {{0, 0}, {1, 2}, {2, 1}, {-1, 2}, {2, -1}, {1, -2}, {-2, 1}, {-1, -2}, {-2, -1}};
long long dist[MAXN][MAXN];
int map[MAXN][MAXN];
int n, m, x, y;

void init(void) {
for(int i = 0; i < 9; i++) {
if(x + attack[i][0] <= n && x + attack[i][0] >= 0) {
if(y + attack[i][1] <= m && y + attack[i][1] >= 0) {
map[x + attack[i][0]][y + attack[i][1]] = true;
}
}
}
}

int main() {
scanf("%d%d%d%d", &n, &m, &x, &y);

init();

int k = 1;
for(int i = 0; i <= n; i++) {
dist[i][0] = map[i][0] ? k = 0 : k;
}
k = 1;
for(int i = 0; i <= m; i++) {
dist[0][i] = map[0][i] ? k = 0 : k;
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
dist[i][j] = map[i][j] ? 0 : dist[i - 1][j] + dist[i][j - 1];
}
}

printf("%lld\n", dist[n][m]);

return 0;
}