1219:马走日
题目要求在给定n×m大小的棋盘,以及马的初始位置(x,y)的情况下,要求不能重复经过棋盘上的同一个点,计算马可以有多少途径遍历棋盘上的所有点。
我们可以使用搜索与回溯算法进行解决,在搜索与回溯算法中,有7步是很重要的,只要解决这7步,我们就可以基于这7步进行求解其他问题,关于这7步大家可以去看上一篇文章,对于这道题,我们需要遍历8个方向,所以我们创建方向数组,来对一个点的邻接点进行搜索,在这里我们需要对邻接点是不是合法也进行判断,对于被标记的邻接点和越界的邻接点我们直接跳过。对于合法的邻接点,我们需要标记,之后搜索下一个棋盘点,那么我们是否需要回溯呢,答案是需要的,例如第一步是往右上跳的,在搜索完这种方案后,我们就需要搜索下一个方案,解除当前方案的标记,
那么我们怎么判断我们走过了几个点呢,我们引入depth参数,每一搜索结束后,都进入下一层进行搜索,那么depth就代表了我们走过了几个点,在终止条件里面,我们对depth进行判断,如果depth == 棋盘点数,我们就对途径数++,这样,我们就可以计算出一共有几种方案,另外注意,本题是有多组输入的,在下一次dfs的开始之前,将标记数组进行清空。
#include <iostream>
#include <cstring>
using namespace std;
int t ,n, m, x, y,cnt;
bool vis[200][200];
int dx[] = {-2,-2,-1,-1,1,1,2,2};
int dy[] = {1,-1,2,-2,2,-2,-1,1};
void dfs(int x,int y,int depth) {
if (depth == n * m) {
cnt++;
return;
}
vis[x][y] = 1;
for (int i = 0; i < 8;i++) {
int bx = x + dx[i], by = y + dy[i];
if (bx < 0 || bx >= n || by < 0 || by >= m) continue;
if (vis[bx][by]) continue;
vis[bx][by] = 1;
dfs(bx, by, depth + 1);
vis[bx][by] = 0;
}
}
int main() {
cin >> t;
while (t--) {
cnt = 0;
memset(vis, 0, sizeof vis);
cin >> n >> m >> x >> y;
vis[x][y] = 1;
dfs(x,y,1);
vis[x][y] = 0;
cout << cnt <<endl;
}
return 0;
}