-、问题描述
8数或15数问题是同一个问题,其就是一个随机排列的8个或15个数在一个方正格子中移动到达规定的一个目标状态。由于只有一个空格子,故只有在空格附近的棋子可以移动。
二、算法描述
F 算法选择
此问题需要对所有可能的路径进行穷举,但是由于随着树的高度的加大,其子结点的增加宿舍剧增,所以对所有的子结点进行穷举是不大现实的。而根据当前的状态和目标状态进行对比可以用一个评估函数来评估当前状态的好坏情况。而在这里我们选择A*算法来进行求解,A*算法是一种最好优先的算法。f'(n) = g'(n) + h'(n),f'(n)是估价函数,g'(n)是起点到终点的最短路径值,这里就表示树的高度,h'(n)是n到目标的最断路经的启发值,其原理是把当前产生的状态和以前所以的状态的评估函数值进行对比,选择其中最小的评估函数继续进行下一步。这里我选择h'(n)的启发值为每个格子到达它的目标位置所需要经过的最少步数。
F 算法描述
需要说明的几点:
1. 用OpenArr表示初始节点列表(待扩展,此为一个动态数组)
2.ClosedArr保存已经访问过的结点
3.算法首先需要给出初始状态,由于随机产生的状态并不一定能够走到目标状态,因此这里采用从标准状态往回走产生一个被打乱的随机状态,这样可以保证有解。
算法实现:
1. OpenArr放置初始结点
2. 如果OpenArr为空集,则退出并给出失败信号
3. n取为OpenArr的第一个节点,并从OpenArr中删除节点n
4. 如果n为目标节点,则退出并给出成功信号
5. 否则,将产生n子节点,并对n的每个子结点n’ 进行如下操作:
1)如果n’ 不在OpenArr和ClosedArr表中,则把n’放入OpenArr表中
2)否则,如果在OpenArr表中,计算评估值,并且如果比表中的评估函数的值小,则更新表中的评估值为当前的值。
3)否则,如果在ClosedArr表中,计算评估值,并且如果比表中的评估函数的值小,则把表中的评估值更新为当前的值,并把该结点从表中删除,并在OpenArr表中加入该结点。
6、把n结点加入ClosedArr中
7、对OpenArr进行排序(根据评估函数从小到大),并转到2。
三、程序设计
算法使用C#语言来实现的。程序主要根据上面提供的广度优先算法的描述来对算法进行实现的。程序共有四个类:
StepNode类,用来描述产生的各个结点的属性以及方法等
Heuristic_15Num_Search类,算法实现类
Form1类,是界面设计的类。
这里分别提供了8数和15数问题的求解。并显示了所经历过的各个状态转移
以下主要对几个核心算法的程序实现进行说明介绍。
//StepNode类 以下几个方法主要是控制格子的左右上下的移动
//0 数字上移
private void MoveUp(Position p)
{
if(p.x>=1)
{
StepNode node = new StepNode();
To(this,node);
Position p1 = new Position(p.x-1,p.y);
AddChild(node,p,p1);
}
}
// 0 数字下移
private void MoveDown(Position p)
{
if(p.x<=text_v.Length-2)
{
StepNode node = new StepNode();
To(this,node);
Position p1 = new Position(p.x+1,p.y);
AddChild(node,p,p1);
}
}
//0 数字左移
private void MoveLeft(Position p)
{
if(p.y>=1)
{
StepNode node = new StepNode();
To(this,node);
Position p1 = new Position(p.x,p.y-1);
AddChild(node,p,p1);
}
}
//0 数字右移
private void MoveRight(Position p)
{
if(p.y<=text_v.Length-2)
{
StepNode node = new StepNode();
To(this,node);
Position p1 = new Position(p.x,p.y+1);
AddChild(node,p,p1);
}
}
//计算节点的启发函数的值
private void ComputeGeuristicGeneVal()
{
int geneVal = this.Height ;
int g = 0; //启发因子 每个数据到达标准位置需要走过的最少步数
for(int i=0;i<text_v.Length;i++)
{
for(int j=0;j<text_v[0].Length;j++)
{
Position p1 = GetPosition(text_v[i][j]);
Position p2 = GetPosition(aim[i,j]);
int xd = p1.x > p2.x ? p1.x - p2.x : p2.x - p1.x ;
int yd = p1.y > p2.y ? p1.y - p2.y : p2.y - p1.y ;
g += xd + yd ;
}
}
geneVal += g;
this.Heuristic_Gene = geneVal;
}
//Heuristic_15Num_Search类
//核心算法实现部分
//循环搜索匹配
private void LoopSearch(StepNode node)
{
while(OpenArr.Count>0)
{
node = (StepNode)OpenArr[0];
OpenArr.Remove(node);
//如果是目标节点则停止搜索
if(node.IsAim())
{
SetPath(node);
return;
}
else
{
//产生子节点。
node.CreateChildren();
//对每个子节点进行检查
foreach(StepNode i in node.Children)
{
//如果不在open和close表中。
if( Contain(ClosedArr,i)==-1 && Contain(OpenArr,i)==-1 )
{
OpenArr.Add(i);
}
//如果在open表中
else if(Contain(OpenArr,i)!=-1)
{
StepNode n = (StepNode)OpenArr[Contain(OpenArr,i)];
//如果i的估计值小于open表中的估计值则替换表中的估计值
if(i.Heuristic_Gene<n.Heuristic_Gene)
{
n.Heuristic_Gene = i.Heuristic_Gene;
}
}
//如果在close中。
else
{
StepNode n = (StepNode)ClosedArr[Contain(ClosedArr,i)];
//如果i的估计值小于closed表中的估计值则替换表中的估计值
if(i.Heuristic_Gene<n.Heuristic_Gene)
{
n.Heuristic_Gene = i.Heuristic_Gene;
ClosedArr.RemoveAt(Contain(OpenArr,i));
OpenArr.Add(n);
}
}
}
//节点加入Closed表中 表示已经访问过了。
ClosedArr.Add(node);
//对节点进行排序
OpenArr.Sort(new MyComparer());
}
}
//理论上不可能出现这种情况
path = "Not Found @!";
return;
}
四、试验结果
1)8数问题搜索路径如下图
Generate 是用来随机产生一个初始状态(46) 表示从标准状态见过随机的46步后产生的一个随机的初始状态。这里46是一个随机数,由于该数越大离目标越远,搜索越复杂故将此随机数控制在0-100之间。3表示3的方正即8数问题,4表示4的方正即表示15数问题。
2)15数问题搜索路径如下图
从以上结果来看,由于使用了启发式的搜索过程,因此大大加快的搜索的速度以及能尽可能经过最少的路径最快到达目标状态,由于8数问题比较简单因此搜索速度较快,而15数问题复杂度加大,当随机产生的数接近100的时候搜索的时间迅速变慢,故算法还待改进,主要是因为随着深度的加深,OpenArr和CloseArr表中的数据迅速扩大,故可以考虑把OpenArr表中的状态数进行选择性的排除一些,比如每次把OpenArr中表的数据经过排序后可以删除最后的几个最差的状态,这样在一定程度上提高了速度但是也减低了找到最优解的几率不过这种减低是非常小的,因为被排除的已经是最差的情况了。
分享到:
相关推荐
通过这个项目,学习者不仅可以了解A*算法的基本原理,还能掌握如何在C#中实现这一算法,同时,通过实际的迷宫演示,能更直观地理解算法的工作机制。对于想要提升算法理解或进行游戏开发的人来说,这是一个非常有价值...
在实际开发中,八数码问题的A*算法实现需要考虑如何有效地存储和操作棋盘状态,如何实现启发式函数,以及如何用C#的编程特性优化代码结构和性能。VS2015作为开发环境,提供了丰富的调试工具和IDE支持,可以帮助...
在这个C#演示程序中,A*算法被巧妙地实现,以帮助开发者理解其核心原理和应用。下面将详细阐述A*算法的基本概念、关键步骤以及在C#中的实现细节。 1. **A*算法概述** A*算法基于Dijkstra算法,但加入了启发式信息...
在压缩包中的"Astar"文件可能包含了实现A*算法的源代码,你可以通过阅读和理解这些代码来学习如何在C#环境中有效地使用A*算法。同时,为了将A*找到的路径进行平滑,你可能还需要参考其他资料来了解如何实现三次B样条...
在C#实现A*寻路算法时,可以使用Unity游戏引擎,利用其内置的图形界面和脚本系统,或者使用Windows Forms或WPF创建独立的应用程序。无论哪种方式,都需要理解C#的基本语法、数据结构和算法,并具备一定的图形界面...
源码通常是用特定编程语言实现的代码,这里提到的是C#语言实现的A*寻路算法。C#是一种面向对象的编程语言,广泛用于Windows平台和Unity3D游戏引擎,因此这个源码可能适用于开发基于C#的游戏或软件。 A*算法的基本...
A*路径搜索算法是一种在图形或网格中寻找从起点到目标点最短路径的优化算法。这个算法在游戏开发、地图导航、机器人路径规划等领域有着广泛的应用。它结合了Dijkstra算法的全局最优性和Best First Search(最佳优先...
这个压缩包文件可能是为了提供一个完整的、适用于Visual Studio 2013的A*算法实现示例。下面我们将详细探讨A*算法及其相关知识点。 A* 算法的核心思想是通过评估节点的启发式成本和实际成本来寻找从起点到终点的...
在C#编程语言中,实现A*算法通常涉及到以下几个关键步骤: 1. 定义地图和节点:将游戏地图抽象为二维数组,每个格子作为节点,包含坐标、状态(是否可通行)等信息。 2. 实现启发式函数:根据游戏规则,设计合适的h...
总的来说,JPS是A*算法在网格路径规划中的优化实践,对于C#开发者来说,理解并实现JPS能提升游戏或其他应用的性能,提供流畅的用户体验。在实现过程中,理解JPS的原理,正确地应用剪枝策略和启发式函数,是确保算法...
C#版A星寻路算法实现+源代码+注释说明 - 不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是个人的毕设,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! 1、该资源内...
DSA(Digital Signature Algorithm)是一种基于离散对数问题的公钥密码学算法,常用于数字签名,以确保数据的完整性和发送者的身份。在C#中实现DSA签名算法,主要涉及以下几个关键步骤和知识点: 1. **密钥生成**:...
在实际应用中,我们可以根据需求选择合适的排列组合算法实现。例如,如果对性能有较高要求,可以考虑使用堆栈方法;而在简单示例或调试阶段,循环方法则更为直观。无论哪种实现方式,理解和掌握排列组合的基本概念...
C#作为Unity的主要编程语言,提供了实现A*算法的良好平台。下面将详细阐述A*算法的基本原理、C#实现方式以及在Unity中的应用。 1. **A*算法基本原理**: A*算法的核心在于结合了Dijkstra算法的全局最优路径寻找和...
在C#编程语言中,掌握几种经典的算法是十分重要的,无论是对初学者还是有经验的开发者,这都能提升解决问题的能力。下面将详细讲解四种在C#中常见的算法,这些算法通常在面试中会被问到,同时也是解决实际问题的基础...
通过研究和理解这个C#版本的Apriori算法实现,不仅可以加深对算法原理的理解,还能提高C#编程能力,特别是处理大规模数据和算法实现方面。对于想要学习数据挖掘、机器学习或者提升软件开发技能的人来说,这是一个...
在Unity3D中,实现A*算法通常会用到脚本语言C#,编写计算和更新节点状态的逻辑。此外,`A╨╟╦π╖¿╤º╧░demo.rar`这个压缩包可能包含了一个A*算法的示例项目,包括场景、脚本、网格数据等,用户可以通过运行和...
5. **C#编程**:Unity3D的主要编程语言是C#,因此A*算法的实现会用到C#的相关知识,包括类、数组、队列等数据结构,以及面向对象编程的概念。 6. **Unity3D集成**:在Unity3D中实现A*寻路,还需要理解Unity的组件...
A星(A*)搜索算法是一种在图形中寻找从起点到终点最短路径...在实际开发中,理解并掌握A*算法的原理和实现细节至关重要,这不仅可以帮助解决游戏中的导航问题,还能够为其他领域如机器人路径规划、网络路由等提供参考。
总的来说,快速排序是一种非常重要的排序算法,理解其工作原理并能用C#或其他编程语言实现,对于提升编程技能和解决问题的能力大有裨益。在实际项目中,根据具体场景选择合适的排序算法是优化程序性能的关键。