A*,八数码

来源:互联网 发布:淘宝卖家怎么看客流量 编辑:程序博客网 时间:2024/05/19 19:43

主要搜索过程:
创建两个表,OPEN表保存所有已生成而未考察的节点,CLOSED表中记录已访问过的节点。
遍历当前节点的各个节点,将n节点放入CLOSE中,取n节点的子节点X,->算X的估价值->

While(OPEN!=NULL)
{

从OPEN表中取估价值f最小的节点n;

if(n节点 in CLOSE) continue;

if(X节点==目标节点)break;//全部子节点
else
{
if(X in OPEN) 比较两个X的估价值f//注意是同一个节点的两个不同路径的估价值
  if( X的估价值小于OPEN表的估价值 )
   更新OPEN表中的估价值; //取最小路径的估价值??

if(X in CLOSE) 比较两个X的估价值//注意是同一个节点的两个不同路径的估价值
  if( X的估价值小于CLOSE表的估价值 )
   把X从CLOSE列表中移除; 把X节点放入OPEN //取最小路径的估价值

if(X not in both)
求X的估价值;
   并将X插入OPEN表中; //还没有排序

}


将n节点插入CLOSE表中;
按照估价值将OPEN表中的节点排序; //实际上是比较OPEN表内节点f的大小,从最小路径的节点向下进行。

}

/*

通过几天的学习启发式搜索以及解决相应的一个算法题,对搜索算法有了进一步的认识.

感谢这些博客主人的翻译:

http://blog.vckbase.com/panic/archive/2005/03/20/3778.aspx

http://blog.vckbase.com/panic/archive/2005/03/28/4144.html

http://www.5igis.com/algorithm/shortpath.htm

http://hi.baidu.com/sonwkuni/blog/item/8be877af32b069cb7dd92a30.html

*/

//我用了stl的优先队列,而且,没有实现去更新open表中的已有的值,我只是用一个新的节点加到open表中

//当然你可以运用自己写的最小堆来维护这个值,有兴趣的可以参考这里:点击打开链接

#include <queue>#include <string>#include <algorithm>#include <cstdio>using namespace std;struct node{  string a;//name  int d;//depth,and the g()'s value  int z;//0's weizhi  int p;//priority,the f()'s value  friend bool operator < (const node & n1, const node & n2)//p值越小优先级越高   {        return n1.p > n2.p;  }  node():d(0),z(0),p(999999999){}};node temp;node now;string start("123456780");//初始化状态 string end("123456780");//最后状态 int fac[10] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};int hash[362881][2];//hash表 :[][0] = 等于0说明还没进过open表,大于0代表已经在open列表中了,而且其值就是f值                    //         [][1] = 大于0代表已经在close列表中了,而且其值就是f值                    int dir[9][4] = {           //0所在位置与交换后可以到达的位置,9表示不能移动到的位置                   {1,3,9,9},//0                  {0,2,4,9},//1                  {1,5,9,9},//2                  {0,4,6,9},//3                  {1,3,5,7},//4                  {2,4,8,9},//5                  {3,7,9,9},//6                  {4,6,8,9},//7                  {5,7,9,9},//8                };int xy[9][2] = {//为每个位置设立坐标                  {1,1},//0                 {1,2},//1                 {1,3},//2                 {2,1},//3                 {2,2},//4                 {2,3},//5                 {3,1},//6                 {3,2},//7                 {3,3},//8                };                  priority_queue<node> q;void init(){  for(int i = 0; i < 9; ++i)   scanf("%s",&end[i]);}int hashindex()//排列与hash {    int result = 0;    string tt = temp.a;    for(int j =1; j < 9; ++j)//从第二个数开始     {        int count = 0;//逆序的个数         for(int k = 0;k < j; ++k) //如果前面的大于后面的则逆序个数+1         {                        if(tt[j] < tt[k]) ++count;        }        result += count*fac[j];//1-9的阶层     }    return result;}int h()//曼哈顿距离 {   string a = end;   string b = temp.a;   int ans = 0;   for(int i = 0; i < 9; ++i)   {      if(b[i] == '0') continue;      for(int j = 0; j < 9; ++j)      {        if(b[i] == a[j])        {          int xx = xy[i][0]-xy[j][0];          if(xx < 0) xx = -xx;//|x1-x2|          int yy = xy[i][1]-xy[j][1];          if(yy < 0) yy = -yy;//|y1-y2|          ans += (xx +yy);// |x1-x2|+|y1-y2|          break;        }      }   }   return ans;}bool bfs(int zz,int xx)//0的位置,被交换的方位 {  temp = now;  temp.a[zz] = temp.a[xx];  temp.a[xx] = '0';  if(temp.a == end)//找到目标节点就返回true    return true;  int isok = hashindex();  temp.d += 1;  temp.z = xx;  temp.p = temp.d+h();    if(hash[isok][1] > 0 && hash[isok][1] > temp.p)//假如已经在close列表中了,而且现在的F值比原来的小   {                                              //说明有更好的路径,因为他们的h值都相同.     hash[isok][1] = 0;//从close表中出去     q.push(temp);    return false;  }    if(hash[isok][0] == 0 || hash[isok][0] > temp.p)//还没在open表中,或者已经在open表中了但是现在的F值比原来的小   {    hash[isok][0] = temp.p;//进入open表或者更新open表中原有的节点的值     q.push(temp);    return false;  }}int A_star(){  int ans = 0;  temp.a = start;  temp.d = 0;  temp.z = 8;  hash[hashindex()][0] = 0;//起始状态   temp.p = 0;  q.push(temp);  while(!q.empty())  {    now = q.top();    q.pop();    temp = now;    int nowhashindex = hashindex();    if(hash[nowhashindex][1] > 0) continue;//如果已经在close表中了就跳过     for(int i = 0; i < 4; ++i)    {      if(dir[now.z][i] < 9 && bfs(now.z,dir[now.z][i]))//如果可以被扩展       {        ans = now.d+1;        return ans;      }    }    hash[nowhashindex][1] = now.p;//进close表   }}int main(){  init();  printf("%d\n",A_star());  return 0;} 

原创粉丝点击