题目描述
棋盘上AA点有一个过河卒,需要走到目标BB点。卒行走的规则:可以向下、或者向右。同时在棋盘上CC点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,AA点(0, 0)(0,0)、BB点(n, m)(n,m)(nn, mm为不超过2020的整数),同样马的位置坐标是需要给出的。
现在要求你计算出卒从AA点能够到达BB点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
输入输出格式
输入格式:
一行四个数据,分别表示BB点坐标和马的坐标。
输出格式:
一个数据,表示所有的路径条数。
输入输出样例
输入样例#1:
6 6 3 3
输出样例#1:
6
说明
结果可能很大!
分析:
思路: 不难想到状态转移方程(请手算模拟样例),设num[i][j]表示第i行第j列的可达路径总数,则对于非边界坐标,都有num[i][j] = num[i-1][j] + num[i][j-1]成立。
对于马的控制点(包括马所在的位置)x, y要使num[x][y] = 0表示不可达,这样做还有一个好处是不会影响到上述递推式的正确性。
注意点:1.题目明确提示应该至少开一个long long二维数组来记录num[][]
2.注意要判断马的控制点是否数组越界和越过(0,0)到(n, m)标识的范围内
3.注意在给第0行以及第0列赋初值时,如果未遇到马的控制点,则赋值为1,一旦遇到了则之后全部为0(在程序中可以直接break)
AC代码:
1 #include12 using namespace std; 13 typedef unsigned long long ULL; 14 const int MAXV = 20 + 10; 15 ULL num[MAXV][MAXV]; 16 int n, m, dx, dy; // B点坐标和马的坐标 17 bool not_arrive[MAXV][MAXV] = {false}; 18 const int X[] = {0, 1, 2, 2, 1, -1, -2, -2, -1}; 19 const int Y[] = {0, -2, -1, 1, 2, 2, 1, -1, -2}; 20 bool ok_loc(int x, int y) { 21 if (x < 0 || x > m || y < 0 || y > n) return false; 22 return true; 23 } 24 25 int main() { 26 //ios::sync_with_stdio(false); 27 scanf("%d %d %d %d", &n, &m, &dx, &dy); 28 for (int i = 0; i < 9; i++) { 29 int x = dx + X[i], y = dy + Y[i]; 30 if (ok_loc(x, y)) not_arrive[x][y] = true; 31 } 32 for (int i = 0; i <= n; i++) { // 0列n行 33 if (!not_arrive[i][0]) num[i][0] = 1; 34 else break; 35 } 36 for (int i = 0; i <= m; i++) { // m列0行 37 if (!not_arrive[0][i]) num[0][i] = 1; 38 else break; 39 } 40 for (int i = 1; i <= n; i++) { 41 for (int j = 1; j <= m; j++) { 42 if (not_arrive[i][j]) num[i][j] = 0; 43 else num[i][j] = num[i][j-1] + num[i-1][j]; 44 } 45 } 46 printf("%llu\n", num[n][m]); 47 48 49 return 0; 50 }