问题描述:
在8×8方格(国际象棋)的棋盘上,从任意指定方格出发,为马寻找一条走遍棋盘每一格并且只经过一次的一条路径。
问题分析:
首先这是一个搜索问题,运用深度优先搜索进行求解是完全可行的,它输入的是全部解,但是马遍历当8×8时解是非常之多的,用天文数字形容也不为过,这样一来求解的过程就非常慢,并且出一个解也非常慢。
怎么才能快速地得到部分解呢?
其实马踏棋盘的问题很早就有人提出,且早在1823年,J.C.Warnsdorff就提出了一个有名的算法。在每个结点对其子结点进行选取时,优先选择‘出口’最小的进行搜索,‘出口’的意思是在这些子结点中它们的可行子结点的个数,也就是‘孙子’结点越少的越优先跳,为什么要这样选取,这是一种局部调整最优的做法,如果优先选择出口多的子结点,那出口少的子结点就会越来越多,很可能出现‘死’结点(顾名思义就是没有出口又没有跳过的结点),这样对下面的搜索纯粹是徒劳,这样会浪费很多无用的时间,反过来如果每次都优先选择出口少的结点跳,那出口少的结点就会越来越少,这样跳成功的机会就更大一些。这种算法称为为贪心算法,也叫贪婪算法或启发式算法,它对整个求解过程的局部做最优调整,它只适用于求较优解或者部分解,而不能求最优解。这样的调整方法叫贪心策略,至于什么问题需要什么样的贪心策略是不确定的,具体问题具体分析。实验可以证明马遍历问题在运用到了上面的贪心策略之后求解速率有非常明显的提高,如果只要求出一个解甚至不用回溯就可以完成,因为在这个算法提出的时候世界上还没有计算机,这种方法完全可以用手工求出解来,其效率可想而知。
算法思想步骤概括为下面的几点:
①找到一个位置的各个方向的出口(OUT1)。
②对各个方向的出口进行二次出口(OUT2)的搜索。
③记录每个方向上出口(OUT1)的二次出口(OUT2),(OUT2)最小的的那个(OUT1)即为接下来要访问的位置。
④将每次访问过的位置放入容器。
使用贪心算法来进行马踏棋盘(8*8国际象棋)的实现如下(C++):
#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
using namespace std;
class Pos //定义棋盘上格子的坐标位置
{
public:
int x;
int y;
Pos(int x, int y):x(x),y(y){}
};