A*,八数码

主要搜索过程:
创建两个表,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;
} 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值