vijos 1360 八数码问题 - 启发式搜索

背景

Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.

描述

在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

格式

输入格式

输入初试状态,一行九个数字,空格用0表示

输出格式

只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

样例1

样例输入1

283104765

样例输出1

4

  这题直接广搜是可以的,不过非常地耗费内存和时间,所以这里用到了A*算法

股价函数是以它和目标节点的差作股价,不过单用股价函数是不可以的(全W的教训)

还要有现在所走的步数,把两者相加,得到优先级,优先级越低的越先搜索

priority = h(x) + step;

   如何说明这个的正确性呢?假设有有一个节点x,h(x) = 2,如果它不能尽快地达到目标状态,以至于优先级超过排在第二的节点y,那么y就会被取出队列进行更新。要使股价函数h(x)的值要减少1(当h(x)=2时是特例),至少需要移动一步,这样就能够保证第一次搜到目标节点一定步数是最少的。如果还不明白,就这么再说一下个人的理解,(h[x]+step)是按照最优的情况移动一次h(x)就减少了1的步数加1进行预算,如果最优的情况下x都不比y优,那么就应当先搜索y。       

Code:

  1 /**
  2  * Vijos.org
  3  * Problem#1360
  4  * Accepted
  5  * Time:76ms
  6  * Memory:996k
  7  **/
  8 #include<iostream>
  9 #include<queue>
 10 #include<set>
 11 using namespace std;
 12 typedef bool boolean;
 13 typedef class MyData{
 14     public:
 15         char datas[3][3];
 16         void in(){
 17             for(int i=0;i<=2;i++){
 18                 for(int j=0;j<=2;j++){
 19                     cin>>datas[i][j];
 20                 }
 21             }
 22         }
 23         MyData(){}
 24         MyData(string str){
 25             for(int i=0;i<=8;i++){
 26                 this->datas[i/3][i%3] = str[i];
 27             }
 28         }
 29         boolean equals(MyData another){
 30             for(int i=0;i<=2;i++){
 31                 for(int j=0;j<=2;j++){
 32                     if(this->datas[i][j]!=another.datas[i][j]) return false;
 33                 }
 34             }
 35             return true;
 36         }
 37         boolean operator <(MyData another) const{
 38             
 39             for(int i=0;i<=2;i++){
 40                 for(int j=0;j<=2;j++){
 41                     if(this->datas[i][j]!=another.datas[i][j]) return this->datas[i][j]<another.datas[i][j];
 42                 }
 43             }
 44             return false;
 45         }
 46 }MyData;
 47 typedef class Node{
 48     public:
 49         int pro;
 50         int step;
 51         MyData d;
 52         int x;
 53         int y;
 54         Node():pro(9),step(0){}
 55         Node(int pro,int step,MyData d):pro(pro),step(step),d(d){}
 56         boolean operator <(Node another) const{
 57             return this->pro>another.pro;
 58         }
 59 }Node;
 60 int fstep = -1;
 61 priority_queue<Node> que;
 62 set<MyData> s;
 63 int m[2][4]={{1,0,-1,0},{0,1,0,-1}};
 64 MyData aim("123804765");
 65 int h(Node node){
 66     int result = 0;
 67     for(int i=0;i<=2;i++){
 68         for(int j=0;j<=2;j++){
 69             if(node.d.datas[i][j]!=aim.datas[i][j]) result++;
 70         }
 71     }
 72     return result;
 73 }
 74 void swap(Node* node,int x,int y,int x1,int y1){
 75     char a=node->d.datas[x][y];
 76     node->d.datas[x][y]=node->d.datas[x1][y1];
 77     node->d.datas[x1][y1]=a;
 78 }
 79 void find(Node start){
 80     start.step = 0;
 81     start.pro=h(start);
 82     for(int a=0;a<=2;a++){
 83         for(int b=0;b<=2;b++){
 84             if(start.d.datas[a][b]=='0'){
 85                 start.x=a;
 86                 start.y=b;
 87                 break;
 88             }
 89         }
 90     }
 91     s.insert(start.d);
 92     que.push(start);
 93     while(!que.empty()){
 94         Node e = que.top();
 95         que.pop();
 96         if(fstep != -1&&e.step >= fstep) continue;
 97         if(e.d.equals(aim)) fstep = e.step;
 98         for(int i=0;i<=3;i++){
 99             Node eu = e;
100             int x=eu.x,y=eu.y;
101             eu.x += m[0][i];
102             eu.y += m[1][i];
103             if(eu.x>=0&&eu.x<=2&&eu.y>=0&&eu.y<=2){
104                 swap(&eu,x,y,eu.x,eu.y);
105                 eu.pro = h(eu) + eu.step + 1;
106                 eu.step++;
107                 if(!s.count(eu.d)){
108                     s.insert(eu.d);
109                     que.push(eu);
110                 }
111             }
112         }
113     }
114 }
115 int main(){
116     MyData d;
117     d.in();
118     find(Node(0,0,d));
119     cout<<fstep;
120     return 0;
121 }

 

posted @ 2016-07-11 21:14  阿波罗2003  阅读(374)  评论(0编辑  收藏  举报