马踏棋盘就是贪心算法的一个很好的应用。先描述下:在国际象棋的8×8棋盘上,随机把马放在一个格子中,马按日字行走进行移动(同中国象棋,无蹩腿,即直走一格再斜走一格),要求每个方格只踏入一次,走遍棋盘上全部64个方格。
下面是我根据前述算法思想用VC实现程序,执行速度没统计,完全小于人的反应时间,先贴运行结果,
先看下程序思路的来源:
早在1823年,J.C.Warnsdorff就提出了一个有名的算法。在每个结点对其子结点进行选取时,优先选择‘出口’最小的进行搜索,‘出口’的意思是在这些子结点中它们的可行子结点的个数,也就是‘孙子’结点越少的越优先跳,为什么要这样选取,这是一种局部调整最优的做法,如果优先选择出口多的子结点,那出口少的子结点就会越来越多,很可能出现‘死’结点(顾名思义就是没有出口又没有跳过的结点),这样对下面的搜索纯粹是徒劳,这样会浪费很多无用的时间,反过来如果每次都优先选择出口少的结点跳,那出口少的结点就会越来越少,这样跳成功的机会就更大一些(来自百度百科)。
好了下面是实现细节:
首先为每个格子定义结构记录坐标(输出时使用),8个子节点指针,有效子节点数量,是否已被push进链表(被踩过),未被踩过的有效子节点数量,回溯次数(用来决定本次的next节点是哪一个孩子节点),如下:
struct stStepNode
{
stGrid grid;
short backtime;//子节点回溯次数
stStepNode* pChirld[8];//8个子节点
short nchildnum;//有效子节点个数
bool bSteped;//是否被踩
stStepNode();
short GetLiveChildNum();//可达子节点个数
};
定义一个list链表listPath,记录已到达的节点顺序,
将初始位置的节点push到listpath,
while(listPath.size()<64)
{
分析链表头节点
if(头节点的 回溯次数 小于有效子节点的个数)
那么把字节点以可达子节点个数 进行升序排列,把第 回溯次数 个子节点 放入链表
else
{
pop
头节点,并把它的数据恢复(回溯次数,是否已入栈);
在将链表中的头节点的回溯次数+1;
}
}
listpath 中就是找到的顺序路径了。
源程序如下,欢迎探讨:
void HorseInChess::HorceStepChess(short x,short y)//初始点
{
stGrid t;
t.x = x;
t.y = y;
if(!IsInChess(t))
{
output("初始点不在棋盘上");
return;
}
Reset();
listPath.push_front(&m_stNode[x][y]);
m_stNode[x][y].bSteped =true;
multimap
mapchild;
multimap::iterator
it;
while(listPath.size()<64)
{
mapchild.clear();
stStepNode* top =
listPath.front();
int n =
top->GetLiveChildNum();
if(n>top->backtime)
{
for(int
i=0; i< top->nchildnum; i++)
{
if(!top->pChirld[i]->bSteped)
{
int
nLiveChildNum =
top->pChirld[i]->GetLiveChildNum();
mapchild.insert(Int_Pair(nLiveChildNum,i));
}
}
int
nNextIndex;int k=0;
for(it=mapchild.begin();it!=mapchild.end();it++,k++)
{
if(k==top->backtime)
{
nNextIndex = it->second;
stStepNode* child = top->pChirld[nNextIndex];
child->bSteped = true;
listPath.push_front(child);
break;
}
} }
else
{
if(listPath.empty())
{
output("路径没找到呢");
listPath.clear();
break;
}
//将出栈的节点恢复初始状态
stStepNode*
popNode = listPath.front();
popNode->bSteped
= false;
popNode->backtime
= 0;
listPath.pop_front();
if(listPath.empty())
{
output("路径没找到呢");
break;
}
stStepNode* top1 = listPath.front();
top1->backtime += 1;
}
}
output("路径找完;啊");
}