A*算法实现8数或者15数问题(C#实现)

原创 2004年10月29日 00:00:00


8
数和15数问题
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

-、问题描述

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表示初始节点列表(待扩展,此为一个动态数组)

2ClosedArr保存已经访问过的结点

3.算法首先需要给出初始状态,由于随机产生的状态并不一定能够走到目标状态,因此这里采用从标准状态往回走产生一个被打乱的随机状态,这样可以保证有解。

算法实现:

1. OpenArr放置初始结点

2. 如果OpenArr为空集,则退出并给出失败信号

3. n取为OpenArr的第一个节点,并从OpenArr中删除节点n

4. 如果n为目标节点,则退出并给出成功信号

5. 否则,将产生n子节点,并对n的每个子结点n’ 进行如下操作:

   1)如果n’ 不在OpenArrClosedArr表中,则把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)

                       {

                            //如果不在openclose表中。

                            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是一个随机数,由于该数越大离目标越远,搜索越复杂故将此随机数控制在0100之间。3表示3的方正即8数问题,4表示4的方正即表示15数问题。

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />

o_8.jpg


        2
15数问题搜索路径如下图

o_15.jpg


    从以上结果来看,由于使用了启发式的搜索过程,因此大大加快的搜索的速度以及能尽可能经过最少的路径最快到达目标状态,由于
8数问题比较简单因此搜索速度较快,而15数问题复杂度加大,当随机产生的数接近100的时候搜索的时间迅速变慢,故算法还待改进,主要是因为随着深度的加深,OpenArrCloseArr表中的数据迅速扩大,故可以考虑把OpenArr表中的状态数进行选择性的排除一些,比如每次把OpenArr中表的数据经过排序后可以删除最后的几个最差的状态,这样在一定程度上提高了速度但是也减低了找到最优解的几率不过这种减低是非常小的,因为被排除的已经是最差的情况了。

 

           请指教,要源代码的email我。


C# A*算法实现8数或者15数问题

 -、问题描述 8数或15数问题是同一个问题,其就是一个随机排列的8个或15个数在一个方正格子中移动到达规定的一个目标状态。由于只有一个空格子,故只有在空格附近的棋子可以移动。 二、算法描述 F 算法...
  • liyingju
  • liyingju
  • 2007年05月29日 16:14
  • 547

A*算法实现8数或者15数问题

-、问题描述8数或15数问题是同一个问题,其就是一个随机排列的8个或15个数在一个方正格子中移动到达规定的一个目标状态。由于只有一个空格子,故只有在空格附近的棋子可以移动。二、算法描述F   算法选择...
  • Tisten
  • Tisten
  • 2004年11月03日 02:07
  • 599

八数码 A*算法

from utils import ( PriorityQueue) import copy infinity = float('inf') def best_first_graph_searc...
  • zzq123686
  • zzq123686
  • 2017年06月01日 07:22
  • 220

PTA 数据结构4-2 多项式求值 (15分)

4-2 多项式求值   (15分) 本题要求实现一个函数,计算阶数为n,系数为a[0] ... a[n]的多项式f(x)=∑i=0n(a[i]×xi)f(x)=\sum_{i=0}^{n}(a[...
  • Summer_Styler
  • Summer_Styler
  • 2017年04月04日 12:35
  • 420

A*算法解决八数码问题 Java语言实现

本文转自:http://www.cnblogs.com/beilin/p/5981483.html 0X00  定义   首先要明确一下什么是A*算法和八数码问题?   A*(A-Star)算法...
  • john_bian
  • john_bian
  • 2017年05月18日 21:47
  • 703

A*算法求解15数码问题

一、问题描述 15数码问题同八数码问题,是人工智能中一个很典型的智力问题。15数码问题是在4×4方格盘上,放有15个数码,剩下一个位置为空(方便起见,用0表示空),每一空格其上下左右的数码可移至空格。...
  • xxy0118
  • xxy0118
  • 2017年01月11日 18:47
  • 1191

问题 A: [贪心算法]删数问题

删数问题 delete.pas/c/cpp 输入一个高精度的正整数n(【输入样例】1754384【输出样例】13 var s:string; i,n,j,k:longint;begin read...
  • jing1223639316
  • jing1223639316
  • 2015年07月10日 09:47
  • 264

经典拼数字游戏NumPuzzle C# By Red_angelX

NumPuzzle 设计说明书背景开发环境:Microsoft Visual Studio .Net 2003开发语言:C# 开发者:Red_angelX1 总体设计设计思路:根据玩家设置的棋盘布局大...
  • Red_angelX
  • Red_angelX
  • 2006年09月29日 16:48
  • 1647

51Nod-1082-与7无关的数

ACM模版描述题解这道题如果暴力解题,超时是一定的,所以需要用到打表来解决。这里需要注意的是数据溢出问题,开始时因为忽略了这个问题,i * i时发生了数据溢出,所以导致大数据测试数据系数WA,找了好久...
  • f_zyj
  • f_zyj
  • 2016年07月30日 16:28
  • 889

[trick]dsu on tree

学习笔记
  • QAQ__QAQ
  • QAQ__QAQ
  • 2016年12月04日 17:56
  • 1782
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:A*算法实现8数或者15数问题(C#实现)
举报原因:
原因补充:

(最多只允许输入30个字)