c++ 启发式搜索解决八数码问题

本文对八数码问题 启发式搜索 (C++)做了一点点修改

  1 //fn=gn+hn
  2 
  3 #include<iostream>
  4 #include<queue>
  5 #include<stack>
  6 
  7 using namespace std;
  8 
  9 #define num 9
 10 
 11 struct node
 12 {
 13     int state[9];//当前状态
 14     struct node* parent;//父节点
 15     int value;//
 16     int depth;//在树中的深度
 17     friend bool operator < (node A, node B) //按照value值小的方案构造优先级队列
 18     {
 19         return A.value > B.value;
 20     }
 21 };
 22 
 23 priority_queue<node> openTable;     //open表
 24 queue<node> closeTable;     //close表
 25 stack<node> Path;     //最终路径
 26 
 27 void init(node& s,node& g)
 28 {//初始化
 29     s.parent=NULL;
 30     s.depth=0;
 31     s.value=0;
 32     g.parent=NULL;
 33     g.depth=0;
 34     g.value=0;
 35 
 36     cout<<"please input the init status"<<endl;
 37     for(int i=0;i<num;i++)
 38     {
 39         cin>>s.state[i];
 40     }
 41 
 42     cout<<"please input the target status"<<endl;
 43     for(int i=0;i<num;i++)
 44     {
 45         cin>>g.state[i];
 46     }
 47 
 48 }
 49 
 50 bool isreachable(node s,node g)
 51 {//判断目标是否可达。若2个状态的逆序奇偶性相同则可达,不相同则不可达。
 52     int count1=0;
 53     int count2=0;
 54     for(int i=0;i<=num-2;i++)
 55     {
 56         for(int j=i+1;j<num;j++)
 57         {
 58             if(s.state[i]>s.state[j]&&s.state[i]*s.state[j]!=0)
 59             {
 60                 count1++;
 61             }
 62         }
 63     }
 64 
 65     for(int i=0;i<=num-2;i++)
 66     {
 67         for(int j=i+1;j<num;j++)
 68         {
 69             if(g.state[i]>g.state[j]&&g.state[i]*g.state[j]!=0)
 70             {
 71                 count2++;
 72             }
 73         }
 74     }
 75 
 76     if(count1%2!=count2%2)
 77     {
 78        return false;
 79     }
 80        return true;
 81 
 82 }
 83 
 84 int value(node a,node g)
 85 {//hn
 86     int count=0;
 87     for(int i=0;i<num;i++)
 88     {
 89         if(a.state[i]==0)
 90         {
 91             continue;
 92         }
 93         else if(a.state[i]!=g.state[i])
 94         {
 95             for(int j=0;j<num;j++)
 96             {
 97                 if(a.state[i]==g.state[j])
 98                 {
 99                     count+=abs(i/3-j/3)+abs(i%3-j%3);
100                 }
101             }
102         }
103     }
104     return count+a.depth;
105 }
106 
107 bool isequal(node a,node g)
108 {//当前节点是否是目标
109     for(int i=0;i<num;i++)
110     {
111         if(a.state[i]!=g.state[i])
112         {
113             return false;
114         }
115     }
116     return true;
117 }
118 
119 bool createNode(node& a,node g)
120 {//产生新节点,加入open表
121     bool flag=true;
122     /* 计算原状态下,空格所在的行列数,从而判断空格可以往哪个方向移动 */
123     int blank;//定义空格下标
124     for(blank=0;blank<num;blank++)
125     {
126         if(a.state[blank]==0)
127         {
128             break;
129         }
130     }
131     if(blank==num)return false;
132     int x=blank/3,y=blank%3;//获取空格所在行列编号
133     /*找到S扩展的子节点,加入open表中*/
134     for(int d=0;d<4;d++)
135     {
136         int newx=x,newy=y;//新空白格坐标
137         node tempnode;//临时节点,子节点
138 
139         /*移动空格*/
140         switch (d)
141         {
142         case 0://向上
143             newx--;
144             if(newx<0)continue;
145             break;
146         case 1://向左
147             newy--;
148             if(newy<0)continue;
149             break;
150         case 2://向下
151             newx++;
152             if(newx>2)continue;
153             break;
154         case 3://向右
155             newy++;
156             if(newy>2)continue;
157             break;
158 
159         default:
160             break;
161         }
162 
163         /*交换新旧空白格的内容*/
164         int newblank=newx*3+newy;//新空格下标
165 
166         if (newx >= 0 && newx < 3 && newy >= 0 && newy < 3)
167         {
168             tempnode=a;
169             tempnode.state[blank]=tempnode.state[newblank];
170             tempnode.state[newblank]=0;
171             if(a.parent!=NULL&&(*a.parent).state[newblank]==0)
172             {//如果新节点和爷爷节点一样,舍弃该节点
173                 continue;
174             }
175 
176             /*把子节点都加入open表中*/
177             tempnode.parent=&a;
178             tempnode.value=value(tempnode,g);
179             tempnode.depth=a.depth+1;
180             openTable.push(tempnode);
181         }
182     }
183     return flag;
184 }
185 
186 bool findpath(node s,node g)
187 {//s->g
188     bool flag=true;
189     /*find path*/
190     openTable.push(s);
191     while(true)
192     {
193         closeTable.push(openTable.top());
194         openTable.pop();
195         if(!isequal(closeTable.back(),g))
196         {
197             flag=createNode(closeTable.back(),g);
198         }
199         else
200         {
201             break;
202         }
203         
204     }
205     /*make path*/
206     node tempnode;
207     tempnode=closeTable.back();
208     while(tempnode.parent!=NULL)
209     {
210         Path.push(tempnode);
211         tempnode=*(tempnode.parent);
212     }
213     Path.push(tempnode);
214     return flag;
215 }
216 
217 void printpath()
218 {//print path s -> g
219     cout<<"move "<<Path.size()-1<<" step"<<endl;
220     while(Path.size()!=0)
221     {
222         for(int i=0;i<num;i++)
223         {
224             cout<<Path.top().state[i]<<" ";
225             if((i+1)%3==0)cout<<endl;
226         }
227         Path.pop();
228         cout<<endl;
229     }
230 }
231 
232 int main()
233 {
234     node s,g;
235     init(s,g);
236     if(!isreachable(s,g))
237     {
238         cout<<"cannot reach"<<endl;
239         system("pause");
240         return 0;
241     }
242     else if (!findpath(s,g))
243     {
244         cout<<"findpath error"<<endl;
245         system("pause");
246         return 0;
247     }
248     else
249     {
250         printpath();
251         cout<<"done"<<endl;
252     }
253     system("pause");
254     return 0;
255 }
View Code

 

posted @ 2019-11-14 21:03  UKC_unknowcry  阅读(566)  评论(0编辑  收藏  举报