题目详情:
1.深度优先搜索。
我看到题目第一反应就是用深度优先搜索,于是写了如下代码:
#include<iostream>
using namespace std;
int n, m, a, b;
int map[21][21]={0};
int movx[8] = { 2,1,-1,-2,-2,-1,1,2 };
int movy[8] = { 1,2,2,1,-1,-2,-2,-1 };
int ans;
void dfs(int x, int y) {
if (x == n && y == m) {
ans += 1;
return;
}
if (x > n || y > m) {
return;
}
int tempx, tempy;
tempx = x + 1;
tempy = y + 1;
if (tempx<=n&&!map[tempx][y]) {
dfs(tempx, y);
}
if (tempy <= m && !map[x][tempy]) {
dfs(x, tempy);
}
return;
}
int main() {
cin >> n >> m >> a >> b;
map[a][b] = 1;
int tempx, tempy;
for (int i = 0; i < 8; i++) {
tempx = a + movx[i];
tempy = b + movy[i];
if (tempx >= 1 && tempx <= n && tempy >= 1 && tempy <= m) {
map[tempx][tempy] = 1;
}
}
ans = 0;
dfs(0, 0);
cout << ans << endl;
return 0;
}
不出我所料,TLE了....
感觉dfs没办法再优化了,做不下去,就可以试试动态规划。
2.动态规划
1).采取一个地图map[n][m]来存储当前图的状态,如果不处于‘马的控制点’,则让map[i][j]=0;
,否则map[i][j]=1;
2)分析:
由于A 只能往 下/右 两个方向走,则 到达B 只能从 B的上面 或者左边。
其实可以观察得出,到B(B的坐标为n,m)的通路 就等于 从上面到B的通路总数 + 从 左边到到B的通路总数。
而其他节点也是一样,先设定:
arr[i][j][0] :从位置(i,j)上方到达位置(i,j)的通路总数
arr[i][j][1] :从位置(i,j)左边到达位置(i,j)的通路总数
则由(0,0)到达(i.j)的所有通路数为:arr[i][j][0] + arr[i][j][1]
可以得到一个递推公式:
arr[i][j][0] = arr[i-1][j][0]+arr[i-1][j][1];
arr[i][j][1] = arr[i][j-1][0]+arr[i][j-1][1];
则答案应该为 arr[n][m][0]+arr[n][m][1]
3).边界处理:
- arr[0][0][1]=arr[0][0][0] = 0;
- arr[i][0][0]=1,arr[i][0][1]=0; (0<i<=n)
- arr[0][j][0]=0;arr[0][j][1]=1; (0<j<=m)
- 代码如下:
arr[0][0][0] = arr[0][0][1] = 0;
for (int i = 1; i <= n; i++) {
arr[i][0][0] = 1;
arr[i][0][1] = 0;
}
for (int i = 1; i <= m; i++) {
arr[0][i][0] = 0;
arr[0][i][1] = 1;
}
4).一些细节:
(1).开 long long
(2).在边界处理的时候,有一些细节要处理,我就被坑了好久..
如果‘马的控制点’是在0这个边界上面的话,那么代码应该改为:
arr[0][0][0] = arr[0][0][1] = 0;
for (int i = 1; i <= n; i++) {
if (map[i][0]) {
for (int j = i; j <= n; j++) {
arr[j][0][0] = arr[j][0][1] = 0;
}
break;
}
arr[i][0][0] = 1;
arr[i][0][1] = 0;
}
for (int i = 1; i <= m; i++) {
if (map[0][i]) {
for (int j = i; j <= m; j++) {
arr[0][j][0] = arr[0][j][1] = 0;
}
break;
}
arr[0][i][0] = 0;
arr[0][i][1] = 1;
}
因为如果边界上有一点为马的控制点,则剩余的节点的路都被截断了.
5).最终代码如下:
#include<iostream>
using namespace std;
int n, m, a, b;
int map[21][21]={0};
int movx[8] = { 2,1,-1,-2,-2,-1,1,2 };
int movy[8] = { 1,2,2,1,-1,-2,-2,-1 };
long long arr[21][21][2];
//arr[i][j][0]:从i,j上面 到达 i,j 的通路总数
//arr[i][j][1]:从i,j左边 到达 i,j 的通路总数
int main() {
cin >> n >> m >> a >> b;
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= m; j++)
map[i][j] = 0;
}
map[a][b] = 1;
int tempx, tempy;
//标记马的控制点
for (int i = 0; i < 8; i++) {
tempx = a + movx[i];
tempy = b + movy[i];
if (tempx >= 0 && tempx <= n && tempy >= 0 && tempy <= m) {
map[tempx][tempy] = 1;
}
}
//初始化边界
arr[0][0][0] = arr[0][0][1] = 0;
for (int i = 1; i <= n; i++) {
if (map[i][0]) {
for (int j = i; j <= n; j++) {
arr[j][0][0] = arr[j][0][1] = 0;
}
break;
}
arr[i][0][0] = 1;
arr[i][0][1] = 0;
}
for (int i = 1; i <= m; i++) {
if (map[0][i]) {
for (int j = i; j <= m; j++) {
arr[0][j][0] = arr[0][j][1] = 0;
}
break;
}
arr[0][i][0] = 0;
arr[0][i][1] = 1;
}
//递推方程
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (!map[i - 1][j]) {
//up,上面是可到达点
arr[i][j][0] = arr[i - 1][j][0] + arr[i - 1][j][1];
}
else {
arr[i][j][0] = 0;
}
if (!map[i][j - 1]) {
//left左边是可到达点
arr[i][j][1] = arr[i][j - 1][0] + arr[i][j - 1][1];
}
else {
arr[i][j][1] = 0;
}
}
}
cout << arr[n][m][0] + arr[n][m][1] << endl;
return 0;
}