背景
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 }