题目描述
解题思路
棋盘 棋盘可以表示为 m a p [ 0... n ] [ 0... m ] map[0...n][0...m] map[0...n][0...m],要注意本题的棋盘是一个大小为 ( n + 1 ) × ( m + 1 ) (n+1) \times (m+1) (n+1)×(m+1) 的矩阵。
不可抵达位置 棋盘上的不可抵达位置包括:
- 马所在的点 ( x , y ) (x, y) (x,y)
- 马的控制点 { ( x 1 , y 1 ) , ∣ x 1 − x ∣ + ∣ y 1 − y ∣ = 3 , x 1 ≠ x , y 1 ≠ y } \{(x_1,y_1), |x_1-x|+|y_1-y|=3, x_1 \neq x, y_1 \neq y\} {(x1,y1),∣x1−x∣+∣y1−y∣=3,x1=x,y1=y}
用一个函数 bool reachable(int x1, int y1)
来判断某一个点是否可达:
bool reachable(int x1, int y1){
if((x1 == x && y1 == y)
|| ((abs(x1-x)+abs(y1-y)==3 && x1!=x && y1!=y))){
return false;
}else{
return true;
}
}
状态转移方程
备忘录 创建一个和棋盘同样大小的备忘录 d p [ 0... n ] [ 0... m ] dp[0...n][0...m] dp[0...n][0...m],其中 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示从棋盘上的 ( 0 , 0 ) (0,0) (0,0)点到 ( i , j ) (i, j) (i,j)点的路径总数, d p [ n ] [ m ] dp[n][m] dp[n][m] 为原问题答案。
- 左上角 d p [ 0 ] [ 0 ] dp[0][0] dp[0][0]:如果第一个位置就不可达,那么后面的所有位置都不可达,可以直接返回总路径条数0;如果第一个位置可达,则将 d p [ 0 ] [ 0 ] dp[0][0] dp[0][0] 初始化为1。
if(!reachable(0, 0)){
// dp[0][0] = 0;
return 0;
}else{
dp[0][0] = 1;
}
- 最左边一行 d p [ i ] [ 0 ] dp[i][0] dp[i][0]:如果 m a p [ i ] [ 0 ] map[i][0] map[i][0] 是不可达位置, d p [ i ] [ 0 ] dp[i][0] dp[i][0]等于0;如果 m a p [ i ] [ 0 ] map[i][0] map[i][0] 可达,到达它的唯一方式就是从 m a p [ i − 1 ] [ 0 ] map[i-1][0] map[i−1][0] 位置向下走一步,因此到达 m a p [ i ] [ 0 ] map[i][0] map[i][0] 的所有路径就是到达 m a p [ i − 1 ] [ 0 ] map[i-1][0] map[i−1][0] 的所有路径再加上一步, d p [ i ] [ 0 ] = d p [ i − 1 ] [ 0 ] dp[i][0] = dp[i-1][0] dp[i][0]=dp[i−1][0]。
for(int i=1; i<=n; i++){
if(!reachable(i, 0)){
dp[i][0] = 0;
}else{
dp[i][0] = dp[i-1][0];
}
}
- 最上边一行 d p [ 0 ] [ j ] dp[0][j] dp[0][j]:与2.同理。
for(int j=1; j<=m; j++){
if(!reachable(0, j)){
dp[0][j] = 0;
}else{
dp[0][j] = dp[0][j-1];
}
}
- 一般情况
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]:如果
m
a
p
[
i
]
[
j
]
map[i][j]
map[i][j] 是不可达位置,
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]等于0;如果
m
a
p
[
i
]
[
j
]
map[i][j]
map[i][j] 可达,有两种方式可以到达:从
m
a
p
[
i
−
1
]
[
j
]
map[i-1][j]
map[i−1][j] 向下走一步、从
m
a
p
[
i
]
[
j
−
1
]
map[i][j-1]
map[i][j−1] 向右走一步,将这两种方式产生的路径条数加起来就是到达
m
a
p
[
i
]
[
j
]
map[i][j]
map[i][j] 位置的路径总数:
d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] dp[i][j] = dp[i-1][j] + dp[i][j-1] dp[i][j]=dp[i−1][j]+dp[i][j−1]
C++代码实现
在实现的时候需要注意:
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 中的值有可能会超过int
的范围,应该用long
。
#include <iostream>
#include <algorithm>
using namespace std;
int n, m, x, y;
void input(){
cin >> n >> m >> x >> y;
}
bool reachable(int x1, int y1){
if((x1 == x && y1 == y)
|| ((abs(x1-x)+abs(y1-y)==3 && x1!=x && y1!=y))){
return false;
}else{
return true;
}
}
long** dp;
long solve(){
dp = new long*[n+1];
for(int i=0; i<=n; i++){
dp[i] = new long[m+1];
}
// init: dp[i][0] = dp[0][j] = 1; dp[x1][y1] = 0;
if(!reachable(0, 0)){
// dp[0][0] = 0;
return 0;
}else{
dp[0][0] = 1;
}
for(int i=1; i<=n; i++){
if(!reachable(i, 0)){
dp[i][0] = 0;
}else{
dp[i][0] = dp[i-1][0];
}
}
for(int j=1; j<=m; j++){
if(!reachable(0, j)){
dp[0][j] = 0;
}else{
dp[0][j] = dp[0][j-1];
}
}
// bottom-up calc
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
if(!reachable(i, j)){
dp[i][j] = 0;
}else{
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
}
return dp[n][m];
}
int main() {
input();
cout << solve();
}