zoukankan      html  css  js  c++  java
  • A*八数码

    帮同学写的八数码,启发式搜索

    创建两个表open,close,分别用的stl中的优先队列priority_queue和map,好久没写过代码了,bug调了半天

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <set>
      5 #include <queue>
      6 #include <algorithm>
      7 #include <vector>
      8 #include <map>
      9 #include <time.h> 
     10 using namespace std;
     11 struct Item        //每一个状态
     12 {
     13     int state[3][3];
     14     int Pre;    //父状态在path中的下标
     15     int F,G,H;    //估计函数 F=G+H
     16     Item(int state[][3],int Pre,int G,int H)    //构造函数
     17     {
     18         this->Pre=Pre;
     19         this->G=G;
     20         this->H=H;
     21         this->F=G+H;
     22         for(int i=0;i<3;i++)
     23             for(int j=0;j<3;j++)
     24                 this->state[i][j]=state[i][j];
     25     }
     26     bool operator <(const Item temp) const        //运算符重载,用于priority_queue中元素的比较
     27     {
     28         return F>temp.F;
     29     }
     30     bool operator ==(const Item temp) const        
     31     {
     32         for(int i=0;i<3;i++)
     33             for(int j=0;j<3;j++)
     34                 if(state[i][j]!=temp.state[i][j])    return 0;
     35         return 1;
     36     }
     37 };
     38 
     39 priority_queue<Item> Open;    //存储扩展出但还没有访问的表
     40 map<int,bool> Close;        //存储已经访问过的节点
     41 vector<Item> path;            //保存路径
     42 int arrays[][3]={0,1,4,2,7,6,3,8,5},arraye[][3]={1,2,3,4,5,6,7,8,0};    //八数码初始状态和目标状态
     43 int dx[]={0,0,-1,1},dy[]={1,-1,0,0};    //四个方向扩展
     44 int CalcuH(const int a0[][3],const int a1[][3])    //CalcuH(当前状态,目标状态)计算 H,如果目标状态和当前状态某个位置数字不同,dis自加1
     45 {
     46     int dis=0;
     47     for(int i=0;i<3;i++)
     48         for(int j=0;j<3;j++)
     49             if(a0[i][j]!=a1[i][j])    dis++;
     50     return dis;
     51 }
     52 bool Judge(const int p0[][3],const int p1[][3])    //两者逆序数奇偶性相等,看八数码是否有解
     53 {
     54     int ss = 0, ee = 0;
     55     for(int i=0; i<9; ++i)
     56         for(int j=0; j<i; ++j) {
     57             if(p0[j/3][j%3] != 0 && p0[j/3][j%3] < p0[i/3][i%3]) ++ss;
     58             if(p1[j/3][j%3] != 0 && p1[j/3][j%3] < p1[i/3][i%3]) ++ee;
     59         }
     60     return (ss&1) == (ee&1);    
     61 }
     62 int GetIndex(const int a[][3])        //获取hash值,将Close[t]设置为1,表示已经访问过
     63 {
     64     int t=0;
     65     for(int i=0;i<3;i++)
     66         for(int j=0;j<3;j++)
     67             t=t*10+a[i][j];
     68     return t;
     69 }
     70 int PrintPath(const Item p)            //递归打印路径
     71 {
     72     if(p.Pre==-1)
     73     {
     74         for(int i=0;i<3;i++)
     75         {
     76             for(int j=0;j<3;j++)
     77                 cout<<"    "<<p.state[i][j]<<" ";
     78             cout<<endl;
     79         }
     80         cout<<endl;
     81         return 0;
     82     }
     83     PrintPath(path[p.Pre]);
     84     cout<<p.G<<" ==>"<<endl;
     85     for(int i=0;i<3;i++)
     86     {
     87         for(int j=0;j<3;j++)
     88             cout<<"    "<<p.state[i][j]<<" ";
     89         cout<<endl;
     90     }
     91     cout<<endl;
     92     return 0;
     93 }
     94 /*search()函数中的思路:
     95     1.将初始节点放入open。(open是优先队列,f最小的节点排在队列的最前面)
     96     2.从open中取出f最小的节点p,放入到path中,如果为目标节点,则递归打印路径。否则将该状态放入到close中,并生成他的扩展节点集P(就是将空白点往四个方向移动)。
     97     3.对于扩展出的每个子节点 temp:
     98         temp.calcuf(),计算f,pre,
     99         如果temp不在close,就把它放入open中,否则不管
    100     4.回到步骤2;
    101 
    102 八数码无解情况判断:
    103     初始状态和目标状态的逆序数奇偶性相同,则可到达
    104 */
    105 void Search(Item s,int end[][3])
    106 {
    107     int x,y,mx,my;
    108     path.clear();
    109     Open.push(s);
    110     while(1)
    111     {
    112         Item e=Open.top();
    113         Open.pop();
    114         path.push_back(e);
    115         int in=GetIndex(e.state);        
    116         Close[in]=1;    //标记表示已经访问过
    117         int len=path.end()-path.begin()-1;        //获取e节点在path中的位置,他是扩展出的节点的父节点。
    118         if(CalcuH(e.state,end)==0)
    119         {
    120             //cout<<e.G<<endl;
    121             cout<<"一共需要"<<e.G<<""<<endl;
    122             PrintPath(e);
    123             return;
    124         }
    125         for(int i=0;i<3;i++)        //找到0的位置,0表示空白
    126             for(int j=0;j<3;j++)
    127                 if(e.state[i][j]==0)
    128                     x=i,y=j;
    129         for(int i=0;i<4;i++)        //向四个方向扩展
    130         {
    131             mx=x+dx[i],my=y+dy[i];
    132             if(mx>2||mx<0||my<0||my>2)    //判断是否跑出3*3的数组
    133                 continue;
    134             swap(e.state[mx][my],e.state[x][y]);    //将空白点与周围点交换位置
    135             Item temp(e.state,len,e.G+1,CalcuH(e.state,arraye));    //构造出新的状态节点
    136             swap(e.state[mx][my],e.state[x][y]);    //再交换回来
    137             int index=GetIndex(temp.state);        //获取hash值
    138             if(!Close.count(index))
    139             {
    140                 Open.push(temp);
    141             }            
    142         }
    143     }
    144     return;
    145 }
    146 int main()
    147 {
    148     clock_t t=clock(),e;
    149     Item s(arrays,-1,0,CalcuH(arrays,arraye));    
    150     if(Judge(arrays,arraye))        //判断是否有解
    151         Search(s,arraye);
    152     else
    153         cout<<"no path"<<endl;
    154     e=clock();
    155     cout<<"run time : "<<e-t<<" ms"<<endl;
    156     return 0;
    157 }
  • 相关阅读:
    关于在MAC上进行 LARAVEL 环境 Homestead 安装过程记录
    js 贷款计算器
    js 实现阶乘
    js 两点间距离函数
    composer Your requirements could not be resolved to an installable set of packages
    vue 项目优化记录 持续更新...
    vue 项目打包
    vue 真机调试页面出现空白
    vue 真机调试
    谈谈-Android状态栏的编辑
  • 原文地址:https://www.cnblogs.com/a1225234/p/5721431.html
Copyright © 2011-2022 走看看