马踏棋盘c语言链表算法,马踏棋盘问题的贪心算法实现

本文介绍了一种使用贪心算法在8×8国际象棋棋盘上,让马按日字行走遍历所有格子的策略。J.C.Warnsdorff提出的算法选择出口最少的子节点优先搜索,避免死结点,提高成功率。程序实现中使用了结构体记录节点信息,并通过链表管理已到达的节点,最终找到了遍历棋盘的路径。
摘要由CSDN通过智能技术生成

马踏棋盘就是贪心算法的一个很好的应用。先描述下:在国际象棋的8×8棋盘上,随机把马放在一个格子中,马按日字行走进行移动(同中国象棋,无蹩腿,即直走一格再斜走一格),要求每个方格只踏入一次,走遍棋盘上全部64个方格。

下面是我根据前述算法思想用VC实现程序,执行速度没统计,完全小于人的反应时间,先贴运行结果,

a4c26d1e5885305701be709a3d33442f.png

先看下程序思路的来源:

早在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("路径找完;啊");

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值