问题:
在 n × n 方格的国际象棋棋盘上,马(也称为骑士Knight)从任意指定的方格出发,以跳马规则(横一步竖两步或横两步竖一步),周游棋盘的每一个格子,要求每个格子只能跳过一次。
思路:
搜索部分就是普通的回溯
void KnightPatrol(int n, int count, step steps[], int map[][8]) {//n表示棋盘规模,count表示骑士已经走过的步数,steps记录骑士巡游过的点,map用来标记地图上每个点有没被走过 if (count == n*n) {//如果骑士巡游过了所有的点 display(steps, n); } for (int i = N; i <= NW; i++) {//对每个方向遍历 step then = overlook(steps[count], i);//向i方向眺望一下 bool lonely = false; if (count % 2 == 0) { lonely = hasLonelyPoint(map, n); } if (isInside(n, then) && !isOverlap(map, then) && !lonely) {//如果骑士下一步没有跑到地图外面,且没有走到刚才走过的地方 //并且地图中没有走不到的点 patrol(steps, count, then, map); KnightPatrol(n, count + 1, steps, map); map[steps[count + 1].x][steps[count + 1].y] = 0; } } }
但是我这里设计了一个剪枝函数,具体思路就是每走一步,就判断下地图中是否有永远不能被走到的点
就是因为这个棒棒哒剪枝函数,运行速度提高了不知道多少
bool hasLonelyPoint(int map[][8], int n) {//判断地图中是否有孤立的点,即怎么都走不到的点 step point1, point2; for (int i = 1; i <= n; i++) { for (int j = 1, count = 0; j <= n; j++) { if (map[i][j] == 0) { point1.x = i; point1.y = j; int count = 0; for (int k = N; k <= NW; k++) { point2 = overlook(point1, k); if (!isInside(n, point2)) count++;//point1 周围的8个点中有点在地图外 if (map[point2.x][point2.y] == 1) count++;//point1 周围的8个点中有点被踩过 } if (count >= 8) return true;//如果8个方向全都不行,说明这个点永远都无法被走到了 } } } return false; }