题目链接:
从起点走到终点,最后一步一定是向右或向下走过来的,因此就可以列出状态转移方程。值得注意的是,对于横着和竖着的两条边界不可直接想当然地认为路径数一定等于 \(1\),因为在中途可能会有控制点的存在,因此还是要老老实实地列出状态转移方程。由于边界时只会从一个方向递推过来,但是初始时下标从 \(1\) 开始导致 \(i=1\) 或 \(j=1\) 时 \(i-1\) 和 \(j-1\) 都是 \(0\),因此也可以直接照搬原本的状态转移方程。
#include <bits/stdc++.h>
using LL = long long;
const int N = 25;
int bx, by, mx, my;
LL f[N][N], s[N][N];
bool check(int x, int y) {//判断马的“控制点”是否合法
if (x < 1 || x > bx || y < 1 || y > by) return false;
return true;
}
int main()
{
std::cin >> bx >> by >> mx >> my;
bx += 1, by += 1, mx += 1, my += 1;//下标从1开始
s[mx][my] = 1;
if (check(mx + 2, my + 1)) s[mx + 2][my + 1] = 1;
if (check(mx + 2, my - 1)) s[mx + 2][my - 1] = 1;
if (check(mx + 1, my + 2)) s[mx + 1][my + 2] = 1;
if (check(mx + 1, my - 2)) s[mx + 1][my - 2] = 1;
if (check(mx - 2, my - 1)) s[mx - 2][my - 1] = 1;
if (check(mx - 2, my + 1)) s[mx - 2][my + 1] = 1;
if (check(mx - 1, my - 2)) s[mx - 1][my - 2] = 1;
if (check(mx - 1, my + 2)) s[mx - 1][my + 2] = 1;
//将所有合法的控制点标记为真
f[1][1] = 1;//如果起点即终点,那么就无需走,这也算一条路径
for (int i = 1; i <= bx; i++) {
for (int j = 1; j <= by; j++) {
if ((i != 1 || j != 1) && !s[i][j]) f[i][j] = f[i - 1][j] + f[i][j - 1];//如果该位置不是控制点,且横纵坐标至少有一个不是1,即不是起点,就可以从两个方向去递推
}
}
std::cout << f[bx][by];
return 0;
}
更易理解的版本:
#include <bits/stdc++.h>
using LL = long long;
const int N = 25;
int bx, by, mx, my;
LL f[N][N], s[N][N];
bool check(int x, int y) {
if (x < 1 || x > bx || y < 1 || y > by) return false;
return true;
}
int main()
{
std::cin >> bx >> by >> mx >> my;
bx += 1, by += 1, mx += 1, my += 1;
s[mx][my] = 1;
if (check(mx + 2, my + 1)) s[mx + 2][my + 1] = 1;
if (check(mx + 2, my - 1)) s[mx + 2][my - 1] = 1;
if (check(mx + 1, my + 2)) s[mx + 1][my + 2] = 1;
if (check(mx + 1, my - 2)) s[mx + 1][my - 2] = 1;
if (check(mx - 2, my - 1)) s[mx - 2][my - 1] = 1;
if (check(mx - 2, my + 1)) s[mx - 2][my + 1] = 1;
if (check(mx - 1, my - 2)) s[mx - 1][my - 2] = 1;
if (check(mx - 1, my + 2)) s[mx - 1][my + 2] = 1;
for (int i = 1; i <= bx; i++) {
for (int j = 1; j <= by; j++) {
if (s[i][j]) f[i][j] = 0;//是控制点就置零
else {
if (i == 1 && j == 1) f[i][j] = 1;//否则的话是起点就置为1
else f[i][j] = f[i - 1][j] + f[i][j - 1];//否则就递推
}
}
}
std::cout << f[bx][by];
return 0;
}
标签:过河,NOIP2002,int,bx,LL,P1002,check,my,mx
From: https://www.cnblogs.com/pangyou3s/p/18116331