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 }

 

posted @ 2016-07-30 17:46  御心飞行  阅读(752)  评论(0编辑  收藏  举报