问题:
在 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;
}