马的遍历进阶版--骑士巡游(添加了评估函数)[Teaks & xgluxv & r]

上周发布了一个简单的马的遍历程序,由于方法不太好,无法有效的解决骑士巡游问题。这次发布的方法则可以在可容忍的时间范围内解决该问题,并且也大幅度提高了非巡游路线的搜索速度,可谓马的遍历进阶版。

所谓骑士巡游问题,即在马的遍历基础上,要求马在踏遍国际象棋棋盘后,如果再走一步,可以回到原出发点,那么本次遍历的路线即满足骑士巡游的要求。

骑士巡游问题其实就是一个哈密尔顿环问题。盲目搜索的话,代价比较大,很久都得不到结果。所以本次的方法中添加了评估函数(Navigator函数),具体方法就是查看下一步的所有候选点中,哪个点所能行动方向最少,那么就优先考虑这个点。这样往后走的时候,剩下的点拥有尽可能多的方向选择,更少机会被堵死,从而可以更快的找到有效解。

呵呵,这个方法是前人研究手工解决骑士巡游问题得到的方法,用纸笔都可解决,更何况用计算机穷搜^_^。

大家同样可下载到C++和C#两个版本的代码,他们所实现的算法是一致的,搜索过程也是完全一样的。

关于用这个算法测试C++和C#的性能问题,我认为不是很全面,毕竟算法只是使用了语言的一小部分功能,故不能完全体现两者的差异,只能大致看一下双方的执行效率。

在我的机器上,C++和C#版(都是Release版)以(0, 0)点为起点搜索到100000条骑士巡游路线(1530348条马的遍历路线)的执行时间大致分别是273.764秒和819.778秒,比值约为1:3。这个比值对于商业软件也许不至于有太多影响,但如果是做游戏的话,可就要好好考虑考虑了。

点击此处下载源代码(vs2005工程文件。C++项目为Win32控制台项目,C#项目基于.Net 2.0)

路漫漫其修远兮 吾将上下而求索

posted @ 2006-03-13 16:40 .Live 阅读(2634) 评论(15)  编辑 收藏 所属分类: 程序算法和技巧

  回复  引用  查看    
#1楼 2006-03-13 18:38 |       
骑士和马有何不同?
  回复  引用  查看    
#2楼 2006-03-13 18:38 |       
有没有人用Java也测试一下?
  回复  引用  查看    
#3楼 [楼主]2006-03-13 19:56 | .Live      
@旻
骑士和马是一样的,都是指国际象棋里的Knight,估计是当初翻译的人喜欢用4个字来概括问题,于是便出现了马的遍历(或叫马踏棋盘)和骑士巡游吧^_^

至于Java,你可以自己修改一份Java版的试试看,将C#或C++的源代码修改为Java的应该不难,你弄好Java版后,别忘了也发我一份看看^_^

-- Teaks
  回复  引用    
#4楼 2006-03-13 22:58 | GoKu [未注册用户]
顺便看了一下两个程序的内存占用情况和处理速度相似,差不多也是1:3
谁弄个VB.Net版的来看看,哈
  回复  引用  查看    
#5楼 2006-03-14 07:07 | xiaotie      
运行模型不一样.同样的代码,在cpp下能优化,在c#下不能优化.将navigator()改成下面代码,能够使性能对比提高为1:2.如果要进一步提高c#代码效率,恐怕得大动程序.

void Navigator()
{
count++;
int NextX, NextY;
int TempX, TempY;

CSPoint point = csPoint[step];
NaviNode[] nodes = point.nodes;

for (int i = 0; i < 8; i++)
{
NextX = point.x + DeltaX[i];
NextY = point.y + DeltaY[i];
nodes[i].dir = i;
nodes[i].score = 0;

if (Board[NextX,NextY] == 0)
{
for (int j = 0; j < 8; j++)
{
TempX = NextX + DeltaX[j];
TempY = NextY + DeltaY[j];

if (Board[TempX,TempY] == 0)
nodes[i].score++;
}
}
else
{
nodes[i].score = 8888;
}
}

int minpos;
int tmp;

for (int i = 0; i < 7; i++)
{
minpos = i;
for (int j = i + 1; j < 8; j++)
{
if (nodes[j].score < nodes[minpos].score)
minpos = j;
}
tmp = nodes[i].score;
nodes[i].score = nodes[minpos].score;
nodes[minpos].score = tmp;
tmp = nodes[i].dir;
nodes[i].dir = nodes[minpos].dir;
nodes[minpos].dir = tmp;
}

}

  回复  引用  查看    
#6楼 2006-03-14 13:07 | SharKoo      
骑士巡游好像是从哪里开始回到哪里吧~~~~~
  回复  引用  查看    
#7楼 [楼主]2006-03-14 13:13 | .Live      
@SharKoo
恩,是的。
文中所指的也是这个意思,只不过说的是在马的遍历基础上的要求而已。

-- Teaks
  回复  引用  查看    
#8楼 2006-03-16 21:56 | A.Z      
re: 马的遍历进阶版--骑士巡游(添加了评估函数)[Teaks & xgluxv & r] 2006-03-14 07:07 xiaotie 回复
运行模型不一样.同样的代码,在cpp下能优化,在c#下不能优化.将navigator()改成下面代码,能够使性能对比提高为1:2.如果要进一步提高c#代码效率,恐怕得大动程序.


呵呵
  回复  引用    
#9楼 2006-04-03 15:56 | 这样说 [未注册用户]
to xiaotie:
引用你的:
如果要进一步提高c#代码效率,恐怕得大动程序
---------------------------------------

我认为你这样说,就没意思了,为了c#的效率提升, 你可以大动程序, 那我用c++也一样可以大动程序呀. 如果你想公平比较, 那我们分别用c++和c#尽自己的所能作到效率最高, 看看到底哪个更强.
  回复  引用    
#10楼 2006-07-11 10:54 | gmcat [未注册用户]
> 哪个点所能行动方向最少,那么就优先考虑这个点。这样往后走的时候,剩下> 的点拥有尽可能多的方向选择,更少机会被堵死

为什么啊?为什么不是行动方向最多啊?
  回复  引用  查看    
#11楼 [楼主]2006-07-12 12:27 | .Live      
@gmcat
因为如果先走行动方向最多的点,那么剩下的点的行动就受到限制,到最后很有可能剩下N多只有一个方向的点,这时搜索失败,浪费很多时间。
相反,如果先走行动方向最少的点,那么剩下的点将拥有更高的灵活度,也就很难赌死了^_^

了解?

[Teaks]
  回复  引用    
#12楼 2006-07-14 14:16 | gmcat [未注册用户]
那选最少方向走岂不是在自寻死路么?就是说要找到多的生路必须先自寻死路 - -||
  回复  引用  查看    
#13楼 [楼主]2006-07-18 12:43 | .Live      
@gmcat
呵呵,不算自寻死路,就是趁着还有很多点可以走,先把行动能力最差的点走掉,这样剩下的点将拥有更高的行动能力。
  回复  引用    
#14楼 2008-04-03 16:44 | 车车 [未注册用户]
有没有算法,看代码有点困难..
  回复  引用    
#15楼 2008-04-03 16:45 | 车车 [未注册用户]
再问,你所求得的条数是所有解吗?


标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2006-03-13 16:42 编辑过


相关链接: