这是一个做题经过+题解
题目传送门
题目简介
你是一个兵,你过河了,现在你在棋盘上(棋盘看成一个坐标系),你要从原点出发到终点,中途不能经过马所能到的所有点
做题经过
一眼看过去这是一道DP题
但是我偏不要DP,很明显DFS更好做,于是我兴高采烈的去写了一串DFS的代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 25;
int n, m, cx, cy, ans;
int vis[maxn][maxn];
int fx[2] = {1, 0}, fcx[8] = {-1, 1, -2, 2, 1, -1, 2, -2};
int fy[2] = {0, 1}, fcy[8] = {-2, 2, -1, 1, -2, 2, -1, 1};
bool bj(int x, int y) {
if (x >= 0 && x <= n && y >= 0 && y <= m) return true;
return false;
}
void dfs(int x, int y) {
if (x == n && y == m) {
ans++;
return;
}
for (int i = 0; i < 2; i++) {
int nx = x + fx[i];
int ny = y + fy[i];
if (!vis[nx][ny] && bj(nx, ny)) {
vis[nx][ny] = 1;
dfs(nx, ny);
vis[nx][ny] = 0;
}
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> cx >>cy;
vis[cx][cy] = 1;
for (int i = 0; i < 8; i++) {
int nx = cx + fcx[i];
int ny = cy + fcy[i];
if (bj(nx, ny)) vis[nx][ny] = 1;
}
if (vis[0][0] || vis[n][m]) {
cout << 0;
return 0;
}
vis[0][0] = 1;
dfs(0, 0);
cout << ans;
return 0;
}
结果
一不小心TLE了,我不甘心,于是去找蒋壮大佬
显然这是可行的,虽然记忆化数组就是DP的状态,但我用的始终还是DFS有点扯我不管
然后我加上了记忆化搜索最后它
问题不大,终于不是TLE了,但是我调了好久始终不知道问题所在,正当我心灰意冷时我看到了一篇帖子,终于我的问题得到了解决,成功的AC了
思路
先标记所有马可能到的点
vis[cx][cy] = 1;
for (int i = 0; i < 8; i++) {
int nx = cx + fcx[i];
int ny = cy + fcy[i];
if (bj(nx, ny)) vis[nx][ny] = 1;
}
然后再进行搜索
ll dfs(ll x, ll y) {
if (x == n && y == m) return 1;
if (mem[x][y] != -1) return mem[x][y];
ll sum = 0;
for (int i = 0; i < 2; i++) {
int nx = x + fx[i];
int ny = y + fy[i];
if (!vis[nx][ny] && bj(nx, ny)) {
vis[nx][ny] = 1;
sum += dfs(nx, ny);
vis[nx][ny] = 0;
}
}
return mem[x][y] = sum;
}
细节1
由于每次都要写边界条件太麻烦了,所以开了个判断边界的函数
bool bj(ll x, ll y) {
return (x >= 0 && x <= n && y >= 0 && y <= m);
}
最后输出答案就可以了
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll maxn = 25;
ll n, m, cx, cy;
ll vis[maxn][maxn], mem[maxn][maxn];
ll fx[2] = {1, 0}, fcx[8] = {-1, 1, -2, 2, 1, -1, 2, -2};
ll fy[2] = {0, 1}, fcy[8] = {-2, 2, -1, 1, -2, 2, -1, 1};
bool bj(ll x, ll y) {
return (x >= 0 && x <= n && y >= 0 && y <= m);
}
ll dfs(ll x, ll y) {
if (x == n && y == m) return 1;
if (mem[x][y] != -1) return mem[x][y];
ll sum = 0;
for (int i = 0; i < 2; i++) {
int nx = x + fx[i];
int ny = y + fy[i];
if (!vis[nx][ny] && bj(nx, ny)) {
vis[nx][ny] = 1;
sum += dfs(nx, ny);
vis[nx][ny] = 0;
}
}
return mem[x][y] = sum;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> cx >>cy;
memset(mem, -1, sizeof mem);
vis[cx][cy] = 1;
for (int i = 0; i < 8; i++) {
int nx = cx + fcx[i];
int ny = cy + fcy[i];
if (bj(nx, ny)) vis[nx][ny] = 1;
}
if (vis[0][0] || vis[n][m]) {
cout << 0;
return 0;
}
vis[0][0] = 1;
ll ans = dfs(0, 0);
cout << ans;
return 0;
}
总结
这道题我把所有能踩的坑都踩了一便,但本质上题目还是比较简单的,希望大家在以后写题的时候不要犯我犯的错误
ps1 如果不懂什么是记忆化搜索的可以看oiwiki,写的很详细
ps2 希望大家可以关注我的洛谷